UOJ#310-[UNR #2]黎明前的巧克力【FWT】

1# 正题
题目链接:https://uoj.ac/problem/310


1|0题目大意

给出一个长度为n的序列,求有多少种方案找出两个集合S,T使得这两个集合的异或和相等。

1n106


2|0解题思路

可以转换为找到一个异或和为0的集合S,产生2|S|的方案数。

然后考虑FWT,那么我们就是要求FWT(1+2xai)

这个东西比较难搞,我们考虑FWT(1+2xai)的性质,FWT(1+2xai)=FWT(1)+FWT(2xai),然后FWT(1)全是1FWT(2xai)的话就有的位置是2有的位置是2,那么最后FWT(1+2xai)出来的只会有31

那么如果我们求出FWT(i=1n1+2xai),这样我们就能求出所有FWT的每一位值的和,又因为总数是n,我们又知道31的和,那我们就能解出31的数量,然后就能求出FWT(1+2xai),再IFWT就好了。

时间复杂度:O(nlogn)


3|0code

#include<cstdio> #include<cstring> #include<algorithm> #define ll long long using namespace std; const ll N=1<<20,P=998244353; ll n,m,a[N]; void FWT(ll *f,ll op){ for(ll p=2;p<=n;p<<=1) for(ll k=0,len=p>>1;k<n;k+=p) for(ll i=k;i<k+len;i++){ ll x=f[i],y=f[i+len]; f[i]=(x+y)*op%P; f[i+len]=(x-y+P)*op%P; } return; } ll power(ll x,ll b){ ll ans=1; while(b){ if(b&1)ans=ans*x%P; x=x*x%P;b>>=1; } return ans; } signed main() { scanf("%lld",&m);n=1<<20; for(ll i=1,x;i<=m;i++) scanf("%lld",&x),a[0]++,a[x]+=2; FWT(a,1); for(ll i=0;i<n;i++){ ll _1=0,_3=0; _3=(a[i]+m)*power(4,P-2)%P;_1=m-_3; a[i]=power(3,_3)*((_1&1)?1:(P-1))%P; } FWT(a,(P+1)/2); printf("%lld\n",P-a[0]-1); return 0; }

__EOF__

本文作者QuantAsk
本文链接https://www.cnblogs.com/QuantAsk/p/16328956.html
关于博主:退役OIer,GD划水选手
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   QuantAsk  阅读(22)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示