版权声明:这是蒟蒻的BLOG,神犇转载也要吱一声哦~ https://blog.csdn.net/Dream_Lolita/article/details/89527100
【题目】
CF
给出三个数
,再给出
组数,每组数包含
个数,
个
,
个
,
个
,那么从每一组数中选择一个数的异或值为
的方案数是多少,对每个
输出答案对
取模
【解题思路】
高妙!
一种暴力的方法是,对于第
组,我们令
,其余为
,然后
个多项式
点积再逆变换就可以得到答案了。
要优化这个暴力,由于只有三个值进行
,那么对于每个位置的贡献情况只有
种,仍然不好考虑。
但我们发现,若将序列整体异或
,即
,现在每一项的系数只有可能是下面四种:
。
考虑每一个位置
,那么就是上面四个贡献的若干次方的乘积,不妨设次方分别为
。
那么我们现在可以得到一个简单的柿子
。考虑再构造出其他的方程使得我们能解出这个东西,于是可以用
和
同号的方案数减去
和
异号的方案数,即仅对
进行
,我们可以得到另一条柿子:
。同理再分别对
和
做
,就可以得到:
。
联立解方程组即可。
复杂度
【参考代码】
#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;
}