CF1710C XOR Triangle

一个常数更小的做法。

对于 \(a \oplus b + b \oplus c = a \oplus c\) ,令 \(A = a \oplus b\)\(B = b \oplus c\) ,则 \(a \oplus c = A \oplus B\)

显然有 \(A \oplus B \leq A + B\)

则需要满足题意,只需扣除存在 \(a \oplus b + b\oplus c = a \oplus c\) 或与其等价式子的三元组即可。

现在我们通过数位 \(dp\) 求解 \(a \oplus b + b\oplus c = a \oplus c\) 的三元组个数。

\(f_{i,0/1,0/1,0/1}\) 表示完成了前 \(i\) 个字符, \(n\) 为给定的字符串 ,\(a,b,c\) 是否与 \(n\) 全部相等的个数。

根据上述条件,每一个二进制位都要满足 \(a \oplus b + b \oplus c = a \oplus c\)

这样的 \((a,b,c)\)\(6\) 种。

\((0,0,0),(0,0,1),(0,1,1),(1,0,0),(1,1,0),(1,1,1)\)\(6\) 种。

根据数位 \(dp\) 的操作转移即可。

具体转移式子可以参考代码。

最后通过容斥将重复算的减去即可。

有两个以上等式的三元组都很容易计算。


#include<cstdio>
const int N=20000020;
const unsigned int mod=998244353;
unsigned long long f[2][2][2][2],now,res,ans;
char s[N];
int main(){
	int i,n=0,o=0;
	scanf("%s",s),f[0][0][0][0]=1;
	for(i=0;s[i];i++,n++)now=now*2%mod,now+=s[i]-'0';
	for(i=0;i<n;i++,o^=1){
		if(s[i]=='0') {
			f[o^1][0][0][0]=f[o][0][0][0];
			f[o^1][1][0][0]=f[o][1][0][0]*2%mod;
			f[o^1][0][0][1]=f[o][0][0][1]*2%mod;
			f[o^1][0][1][1]=f[o][0][1][1]*3%mod;
			f[o^1][1][0][1]=f[o][1][0][1]*3%mod;
			f[o^1][1][1][0]=f[o][1][1][0]*3%mod;
			f[o^1][1][1][1]=f[o][1][1][1]*6%mod; 
		}
		else {
			f[o^1][0][0][0]=f[o][0][0][0];
			f[o^1][1][0][0]=(f[o][1][0][0]*2+f[o][0][0][0])%mod;
			f[o^1][0][0][1]=(f[o][0][0][1]*2+f[o][0][0][0])%mod;
			f[o^1][0][1][1]=(f[o][0][1][1]*3+f[o][0][0][1]+f[o][0][1][0]*2+f[o][0][0][0])%mod;
			f[o^1][1][0][1]=(f[o][1][0][1]*3+f[o][0][0][1]+f[o][1][0][0])%mod;
			f[o^1][1][1][0]=(f[o][1][1][0]*3+f[o][1][0][0]+f[o][0][1][0]*2+f[o][0][0][0])%mod;
			f[o^1][1][1][1]=(f[o][1][1][1]*6+f[o][0][1][1]*3+f[o][1][0][1]*3+f[o][1][1][0]*3+f[o][0][0][1]*2+f[o][1][0][0]*2+f[o][0][0][0])%mod;
		}
	}
	for(i=0;i<8;i++)res=(res+f[o][i&1][(i>>1)&1][(i>>2)&1])%mod;
	now=(now+1)%mod,ans=(1llu*4*mod+now*now%mod*now+3*now%mod*now-now-3*res)%mod;
	printf("%lld\n",(ans+mod)%mod);
	return 0;
}

把第一维彻底压去。

#include<cstdio>
const int N=20000020;
const unsigned int mod=998244353;
unsigned long long f[2][2][2],now,res,ans;
char s[N];
int main(){
	int i,n=0,o=0;
	fread(s,1,N,stdin);
	for(i=0;s[i]>='0'&&s[i]<='1';i++,n++)now=now*2%mod,now+=s[i]-'0';
	for(i=0;i<n;i++,o^=1){
		if(s[i]=='0') {
			f[1][0][0]=f[1][0][0]*2%mod;
			f[0][0][1]=f[0][0][1]*2%mod;
			f[0][1][1]=f[0][1][1]*3%mod;
			f[1][0][1]=f[1][0][1]*3%mod;
			f[1][1][0]=f[1][1][0]*3%mod;
			f[1][1][1]=f[1][1][1]*6%mod; 
		}
		else {
			f[1][1][1]=(f[1][1][1]*6+f[0][1][1]*3+f[1][0][1]*3+f[1][1][0]*3+f[0][0][1]*2+f[1][0][0]*2+1)%mod;
			f[0][1][1]=(f[0][1][1]*3+f[0][0][1]+f[0][1][0]*2+1)%mod;
			f[1][0][1]=(f[1][0][1]*3+f[0][0][1]+f[1][0][0])%mod;
			f[1][1][0]=(f[1][1][0]*3+f[1][0][0]+f[0][1][0]*2+1)%mod;
			f[1][0][0]=(f[1][0][0]*2+1)%mod;
			f[0][0][1]=(f[0][0][1]*2+1)%mod;
		}
	}
	for(i=1;i<8;i++)res=(res+f[i&1][(i>>1)&1][(i>>2)&1])%mod;res=res+1;
	now=(now+1)%mod,ans=(1llu*4*mod+now*now%mod*now+3*now%mod*now-now-3*res)%mod;
	printf("%lld\n",(ans+mod)%mod);
	return 0;
}
posted @ 2022-07-28 23:26  Qzong  阅读(87)  评论(0)    收藏  举报