[关闭]
@xzyxzy 2018-07-23T11:40:39.000000Z 字数 1425 阅读 1219

[UOJ310]黎明前的巧克力

题解

作业部落

评论地址


TAG:FWT

题意

在集合中选出任意多数,使得异或和为,再将其分为两个有区别的可空集合的方案数(两集合不能都为空)

题解

考虑生成函数
如果选出一个异或和为的集合大小为,那么对答案的贡献就是,于是把系数置为
假设个数的生成函数为,分别为
那么答案就是(异或卷积)
我们可以把每个生成函数的次项置为,那么答案就直接是

就应该是(每一位对应乘)
然后再把回来就是答案了
由于的可加性(证明戳我

而且每个多项式都很特殊,位上为会对每一位做贡献,位为会对一些位做的贡献对另一些位做的贡献(因为是异或卷积所以每一位的数后都会对所有的位造成影响),由此每一位要么为要么为
所以按位加,共个多项式,最后的值为,则的个数为,可以得到该位上的总个数
最后是要乘起来的,所以只是变符号,就是的该位的值了,最后回来即为答案(多算了全是空集的一种情况)

代码

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstdlib>
  4. #include<cstring>
  5. using namespace std;
  6. int read()
  7. {
  8. char ch=getchar();int h=0,t=1;
  9. while((ch>'9'||ch<'0')&&ch!='-') ch=getchar();
  10. if(ch=='-') t=-1,ch=getchar();
  11. while(ch>='0'&&ch<='9') h=h*10+ch-'0',ch=getchar();
  12. return h*t;
  13. }
  14. const int mod=998244353;
  15. const int N=1<<21;
  16. const int inv=499122177;
  17. int n,A[N],B[N],bit3[N],l;
  18. void FWT_xor(int *P,int op)
  19. {
  20. for(int i=1;i<l;i<<=1)
  21. for(int j=0,p=i<<1;j<l;j+=p)
  22. for(int k=0;k<i;k++)
  23. {
  24. int X=P[j+k],Y=P[j+k+i];
  25. P[j+k]=1ll*(X+Y)%mod*op%mod;
  26. P[j+k+i]=1ll*((X-Y)%mod+mod)*op%mod;
  27. }
  28. }
  29. int main()
  30. {
  31. n=read();A[0]=n;bit3[0]=1;int mx=0;
  32. for(int i=1;i<=n;i++) bit3[i]=bit3[i-1]*3ll%mod;
  33. for(int i=1,x;i<=n;i++) A[x=read()]+=2,mx=max(mx,x);
  34. for(l=1;l<=mx;l<<=1);
  35. FWT_xor(A,1);
  36. for(int i=0;i<l;i++)
  37. {
  38. int x=(3ll*n-A[i]+mod)*inv%mod*inv%mod;
  39. A[i]=bit3[n-x]; if(x&1) A[i]=mod-A[i];
  40. }
  41. FWT_xor(A,inv);
  42. printf("%d\n",(A[0]-1+mod)%mod);
  43. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注