fogflea
fogflea
发布于 2025-10-14 / 3 阅读
0
0

[THUPC 2021 初赛] 合法序列

传送门

k 太小了,结合题目易于想到枚举前 2^k 位的状态,然后限制不是一般算法能做的,考虑 \texttt{dp} ,每加一位贡献只跟前 k-1 位有关,设进状态转移,设 f_{i,j} 表示考虑到第 i 位,后 k-1 位状态为 j 的方案数,每次转移分别考虑 j 新加一位 0 1 是否合法就行,O(2^{2^k+k-1}n)

#include<bits/stdc++.h>
using namespace std;
using ll=long long;
const ll mod=998244353;
int n,k;
ll f[501][11];
ll ans;
int rev(int x){
	int res=0;
	for(int i=0;i<k;++i)
		res|=(((x>>(k-1-i))&1)<<i);
	return res;
}
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin>>n>>k;
	for(int s=0;s<(1<<(1<<k));++s){
		#define chk(s,x) (s&(1<<(rev(x))))
		bool fl=0;
        //判一下枚举的 s 合不合法
		for(int i=0,tmp=s%(1<<k-1);i+k-1<(1<<k);++i){
			tmp|=(((s>>(i+k-1))&1)<<k-1);
			if(!chk(s,tmp)){
				fl=1;
				break;
			}
			tmp>>=1;
		} 
		if(fl)continue;
		memset(f,0,sizeof f);
		f[(1<<k)-1][s>>((1<<k)-k+1)]=1;
		for(int i=(1<<k)-1;i<n-1;++i){
			for(int j=0;j<(1<<k-1);++j){
				if(!f[i][j])continue;
				if(chk(s,j))(f[i+1][j>>1]+=f[i][j])%=mod;
				if(chk(s,j|(1<<k-1)))(f[i+1][(j|(1<<k-1))>>1]+=f[i][j])%=mod;
			}
		}
		for(int i=0;i<(1<<k-1);++i){
			(ans+=f[n-1][i])%=mod;
		}
	}
	cout<<ans;
	return 0;
}

评论