Cyclic Hamming (Hard Version)

Cyclic Hamming (Hard Version)

考虑 \(\sum h(s,t') = cnt_{0,s} \times cnt_{1,t} + cnt_{1,s} \times cnt_{0,t} = 2^{2k+1}\),则 \(h(s,t)\) 的平均数为 \(\dfrac{2^{2k+1}}{2^{k+1}}=2^k\),然而我们要求所有的 \(h(s,t') \geq 2^k\),故所有的 \(h(s,t') = 2^k\)

由于 \(cnt_{0,s} = cnt_{1,s} = cnt_{0,t} = cnt_{1,t} = 2^k\),故 \(h(s,t')=2^k\) 等价于满足 \(s_i = t'_i = 1\) 的位置 \(i\)\(2^{k-1}\) 个,下面我们用新的方式刻画。

构造 \(F=\sum s_i x^i\)\(G=\sum t_{n-i-1} x^i\),故我们要求 \(F \times G \equiv 2^{k-1} \times \sum\limits_{i=0}^{2^{k+1}-1} x^i \pmod {x^{2^{k+1}}-1}\)

我们将其化为 \(F \times G = 2^{k-1} \times \sum\limits_{i=0}^{2^{k+1}-1} x^i + C \times (x^{2^{k+1}}-1) = 2^{k-1} \times \sum\limits_{i=0}^{2^{k+1}-1} x^i + C \times (x-1) \times \sum\limits_{i=0}^{2^{k+1}-1} = \sum\limits_{i=0}^{2^{k+1}-1} \times ((x-1)C + 2^{k-1}) = ((x-1)C + 2^{k-1}) \times \prod\limits_{i=0}^k (x^{2^i} + 1)\)

首先要求 \(x^{2^i} + 1 \mid F \times G\),其次要求 \(\dfrac{F \times G}{\prod\limits_{i=0}^k (x^{2^i} + 1)} = (x-1)C + 2^{k-1}\),即 \(\dfrac{F \times G}{\prod\limits_{i=0}^k (x^{2^i} + 1)} \equiv 2^{k-1} \pmod {x-1}\)。而一个多项式对 \((x-1)\) 取模后的结果为其带入 \(x=1\) 后的值,而 \(\dfrac{F(1) \times G(1)}{\prod\limits_{i=0}^k (1^{2^i} + 1)} = \dfrac{2^k \times 2^k}{2^{k+1}} = 2^{k-1}\),故第二个条件成立。

同时我们发现 \(x^{2^i}+1\) 在本题使用的数域下不可约,故只要求 \(x^{2^i} + 1 \mid F\)\(x^{2^i} + 1 \mid G\)

考虑对于 \(i \in [0,k]\),将 \(x\) 的次数按照模 \(2^i\) 分类,系数重组构成的新多项式是 \(x+1\) 的倍数,也就是带入 \(x=-1\) 后多项式的值为 \(0\)

考虑建立 trie 树,对于为 \(1\) 的下标 \(i\) 从低到高将二进制位插入 trie,则上式等价于每个非叶节点左子树和右子树中的叶子个数相同,接下来对其 dp。

具体地,我们令 \(dp_{u,S,t}\) 表示在 \(u\) 的子树中,满足条件的 \(i\)\(S\),选了 \(t\) 个叶子的方案数,这是容易 dp 的,可以获得 \(O(16^k)\) 的做法。

然而我们枚举 \(S\),复杂度可以变为 \(O(8^k)\),接下来我们精细分析一下复杂度。

发现每次需要左右相同,都会让有值的 gap 变成 \(2\) 倍,再加点小优化。

image

//Ad astra per aspera
#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
const long long mod=998244353;
int k;
char s[1<<13],t[1<<13];
int siz[1<<14],depth[1<<14],dp_len[1<<14];
long long ans[1<<13],ans_s[1<<13],ans_t[1<<13];
vector<long long> dp[1<<14];
void solve(){
	int lst_S=-1;
	for(int SS=0;SS<(1<<(k+1));SS++){
		int S=0;
		for(int i=0;i<=k;i++){
			if(SS&(1<<i)){
				S+=(1<<(k-i));
			}
		}
		int p=0;
		if(lst_S!=-1){
			for(int i=0;i<=k;i++){
				bool f_lst,f_now;
				if(lst_S&(1<<i)){
					f_lst=true;
				}
				else{
					f_lst=false;
				}
				if(S&(1<<i)){
					f_now=true;
				}
				else{
					f_now=false;
				}
				if(f_lst!=f_now){
					p=i;
					break;
				}
			}
		}
		p=(1<<(k+1-p))-1;
		dp[1][(1<<k)]=0;
		for(int u=p;u>=1;u--){
			if(S&(1<<depth[u])){
				for(int j=0;j<=siz[u*2];j+=dp_len[u*2]){
					dp[u][j*2]=dp[u*2][j]*dp[u*2+1][j];
					dp[u][j*2]%=mod; 
				}
				dp_len[u]=dp_len[u*2]*2;
			}
			else{
				for(int i=0;i<=siz[u*2]+siz[u*2+1];i+=dp_len[u*2]){
					dp[u][i]=0;
				}
				for(int i=0;i<=siz[u*2];i+=dp_len[u*2]){
					for(int j=0;j<=siz[u*2+1];j+=dp_len[u*2+1]){
						dp[u][i+j]+=dp[u*2][i]*dp[u*2+1][j];
						dp[u][i+j]%=mod; 
					}
				}
				dp_len[u]=dp_len[u*2];
			}
		}
		ans[S]=dp[1][(1<<k)];
		lst_S=S;
	}
	for(int i=0;i<=k;i++){
		for(int j=0;j<(1<<(k+1));j++){
			if(j&(1<<i)){
				ans[j-(1<<i)]=((ans[j-(1<<i)]-ans[j])%mod+mod)%mod;
			}
		}
	}
}
int main(){
	scanf("%d",&k);
	for(int i=0;i<(1<<(k+1));i++){
		cin>>s[i];
	}
	for(int i=0;i<(1<<(k+1));i++){
		cin>>t[i]; 
	}
	for(int i=(1<<(k+2))-1;i>=1;i--){
		if(i>=(1<<(k+1))){
			siz[i]=1;
			depth[i]=-1;
			dp_len[i]=1;
		}
		else{
			siz[i]=siz[i*2]+siz[i*2+1];
			depth[i]=depth[i*2]+1;
		}
		for(int j=0;j<=siz[i];j++){
			dp[i].push_back(0);
		}
	}
	for(int i=(1<<(k+1));i<(1<<(k+2));i++){
		int tmp=i-(1<<(k+1)),pre=0;
		for(int j=0;j<=k;j++){
			if(tmp&(1<<j)){
				pre+=(1<<(k-j));
			}
		}
		if(s[pre]=='0'){
			dp[i][0]=1;
			dp[i][1]=0;
		}
		if(s[pre]=='1'){
			dp[i][0]=0;
			dp[i][1]=1;
		}
		if(s[pre]=='?'){
			dp[i][0]=1;
			dp[i][1]=1;
		}
	}
	solve();
	for(int i=0;i<(1<<(k+1));i++){
		ans_s[i]=ans[i];
	}
	for(int i=(1<<(k+1));i<(1<<(k+2));i++){
		int tmp=i-(1<<(k+1)),pre=0;
		for(int j=0;j<=k;j++){
			if(tmp&(1<<j)){
				pre+=(1<<(k-j));
			}
		}
		if(t[pre]=='0'){
			dp[i][0]=1;
			dp[i][1]=0;
		}
		if(t[pre]=='1'){
			dp[i][0]=0;
			dp[i][1]=1;
		}
		if(t[pre]=='?'){
			dp[i][0]=1;
			dp[i][1]=1;
		}
	}
	solve();
	for(int i=0;i<(1<<(k+1));i++){
		ans_t[i]=ans[i];
	}
	long long final_ans=0;
	for(int i_s=0;i_s<(1<<(k+1));i_s++){
		for(int i_t=0;i_t<(1<<(k+1));i_t++){
			if((i_s|i_t)==(1<<(k+1))-1){
				final_ans+=ans_s[i_s]*ans_t[i_t]%mod;
				final_ans%=mod;
			}
		}
	}
	printf("%lld\n",final_ans);
	return 0;
}
posted @ 2026-08-05 10:59  Oken喵~  阅读(3)  评论(0)    收藏  举报