【FWT】CF1119H Triple

版权声明:这是蒟蒻的BLOG,神犇转载也要吱一声哦~ https://blog.csdn.net/Dream_Lolita/article/details/89527100

【题目】
CF
给出三个数 x , y , z x,y,z ,再给出 n n 组数,每组数包含 ( x + y + z ) (x+y+z) 个数, x x a a , y y b b , z z c c ,那么从每一组数中选择一个数的异或值为 t t 的方案数是多少,对每个 t t 输出答案对 998244353 998244353 取模
n 1 0 5 , k 2 1 7 , a , b , c < 2 k n\leq 10^5,k\leq 2^17,a,b,c< 2^k

【解题思路】
高妙!
一种暴力的方法是,对于第 i i 组,我们令 f i , a i = x , f i , b i = y , f i , c i = z f_{i,a_i}=x,f_{i,b_i}=y,f_{i,c_i}=z ,其余为 0 0 ,然后 n n 个多项式 FWT \text{FWT} 点积再逆变换就可以得到答案了。

要优化这个暴力,由于只有三个值进行 FWT \text{FWT} ,那么对于每个位置的贡献情况只有 8 8 种,仍然不好考虑。
但我们发现,若将序列整体异或 a i a_i ,即 f i , 0 = x , f i , a i b i = y , f i , a i c i = z f_{i,0}=x,f_{i,a_i\oplus b_i}=y,f_{i,a_i\oplus c_i}=z ,现在每一项的系数只有可能是下面四种: x + y + z , x + y z , x y + z , x y z x+y+z,x+y-z,x-y+z,x-y-z

考虑每一个位置 i ( 0 i < 2 k ) i(0\leq i<2^k) ,那么就是上面四个贡献的若干次方的乘积,不妨设次方分别为 a , b , c , d a,b,c,d
那么我们现在可以得到一个简单的柿子 a + b + c + d = n a+b+c+d=n 。考虑再构造出其他的方程使得我们能解出这个东西,于是可以用 x x y y 同号的方案数减去 x x y y 异号的方案数,即仅对 f a i b i = 1 f_{a_i\oplus b_i}=1 进行 FWT \text{FWT} ,我们可以得到另一条柿子: a + b c d = c n t 1 a+b-c-d=cnt_1 。同理再分别对 x , z x,z y , z y,z FWT \text{FWT} ,就可以得到: a b + c d = c n t 2 , a b c + d c n t 3 a-b+c-d=cnt_2,a-b-c+d-cnt_3

联立解方程组即可。

复杂度 O ( k 2 k ) O(k\cdot 2^k)

【参考代码】

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int N=262333,mod=998244353,inv2=(mod+1)>>1;
int n,k,X,Y,Z,inv4,tmp;
int ans[N],A[N],B[N],C[N];

int read()
{
	int ret=0;char c=getchar();
	while(!isdigit(c)) c=getchar();
	while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
	return ret;
}
int upm(int x){return x>=mod?x-mod:(x<0?x+mod:x);}
void up(int &x,int y){x=upm(x+y);}
int mul(int x,int y){return 1ll*x*y%mod;}
int qpow(int x,int y){int res=1;for(;y;y>>=1,x=mul(x,x))if(y&1)res=mul(res,x);return res;}

void fwtxor(int *a,int n,int op)
{
	for(int i=1;i<n;i<<=1) 
		for(int j=0;j<n;j+=i<<1)
			for(int k=0;k<i;++k)
			{
				ll x=a[j+k],y=a[i+j+k];
				a[j+k]=upm(x+y);a[i+j+k]=upm(x-y);
				if(!~op) a[j+k]=mul(a[j+k],inv2),a[i+j+k]=mul(a[i+j+k],inv2);
			}
}

int main()
{
#ifdef Durant_Lee
	freopen("CF1119H.in","r",stdin);
	freopen("CF1119H.out","w",stdout);
#endif
	n=read();k=read();X=read();Y=read();Z=read();inv4=qpow(4,mod-2);
	for(int i=1;i<=n;++i)
	{
		int a=read(),b=read(),c=read();
		tmp^=a;A[a^b]++;B[a^c]++;C[b^c]++;
	}
	fwtxor(A,1<<k,1);fwtxor(B,1<<k,1);fwtxor(C,1<<k,1);
	//for(int i=0;i<(1<<k);++i) printf("%d ",C[i]); puts("");
	for(int i=0;i<(1<<k);++i)
	{
		//printf("%d %d %d\n",A[i],B[i],C[i]);
		ll a=upm(((ll)n+A[i]+B[i]+C[i])%mod*inv4%mod),b=upm(((ll)n+A[i]-B[i]-C[i])%mod*inv4%mod);
		ll c=upm(((ll)n-A[i]+B[i]-C[i])%mod*inv4%mod),d=upm(((ll)n-A[i]-B[i]+C[i])%mod*inv4%mod);
		//printf("%lld %lld %lld %lld\n",a,b,c,d);
		ans[i]=1ll*qpow(((ll)X+Y+Z)%mod,a)*qpow(((ll)X+Y-Z)%mod,b)%mod*qpow(((ll)X-Y+Z)%mod,c)%mod*qpow(((ll)X-Y-Z)%mod,d)%mod;
		ans[i]=upm(ans[i]);
	}
	fwtxor(ans,1<<k,-1);
	for(int i=0;i<(1<<k);++i) printf("%d ",ans[i^tmp]);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Dream_Lolita/article/details/89527100
今日推荐