uoj310. UNR #2黎明前的巧克力
Posted liguanlin1124
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了uoj310. UNR #2黎明前的巧克力相关的知识,希望对你有一定的参考价值。
题目描述:
题解:
WTF。
看题解看了一个小时才看明白。
首先有状态$f[i][j]$表示前$i$个东西两人取,最后两人异或和为$j$的有多少方案。
转移为$f[i][j]=f[i-1][j]+2*f[i-1][j \oplus a[i]]$。
显然跑FWT做异或卷积(显然会T)。
发现卷积中每次卷的是1,0,0,……,0,2,0……这样一个东西。
打表发现FWT后每一项是-1或3。
其实很好解释,从贡献的角度讲,0位的贡献都是1,而$a[i]$位的贡献是2或-2,所以是3或-1。
考虑将所有的$a[i]$放在一起做FWT。
这样的话每组对每一位上的贡献是-1或3,共有$n$组,贡献和为$s$。
设贡献为$3$的有$x$组,那么$3x-(n-x)=s$,有$x=\fracn+s4$。
然后快速幂再卷回去就好了。
代码:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; const int N = 2000050; const int MOD = 998244353; const int inv_2 = (MOD+1)/2; const int inv_4 = 1ll*inv_2*inv_2%MOD; template<typename T> inline void read(T&x) T f = 1,c = 0;char ch=getchar(); while(ch<‘0‘||ch>‘9‘)if(ch==‘-‘)f=-1;ch=getchar(); while(ch>=‘0‘&&ch<=‘9‘)c=c*10+ch-‘0‘;ch=getchar(); x = f*c; template<typename T>inline void Mod(T&x)if(x>=MOD)x-=MOD; ll fastpow(ll x,int y) ll ret = 1; while(y) if(y&1)ret=ret*x%MOD; x=x*x%MOD;y>>=1; return ret; int n,a[N],lim; void fwt(int*a,int len,int k) for(int i=1;i<len;i<<=1) for(int j=0;j<len;j+=(i<<1)) for(int o=0;o<i;o++) int w1 = a[j+o],w2 = a[j+o+i]; Mod(a[j+o] = w1+w2),Mod(a[j+o+i]=w1+MOD-w2); if(k==-1)a[j+o]=1ll*a[j+o]*inv_2%MOD,a[j+o+i]=1ll*a[j+o+i]*inv_2%MOD; int main() read(n);int mx=0; for(int i=1,x;i<=n;i++) read(x); if(x>mx)mx=x; a[0]++,a[x]+=2; lim = 1; while(lim<=mx)lim<<=1; fwt(a,lim,1); for(int i=0;i<lim;i++) int now = 1ll*(n+a[i])*inv_4%MOD; a[i] = fastpow(3,now); if((n-now)&1)a[i]=MOD-a[i]; fwt(a,lim,-1); printf("%d\n",(a[0]+MOD-1)%MOD); return 0;
以上是关于uoj310. UNR #2黎明前的巧克力的主要内容,如果未能解决你的问题,请参考以下文章