大容斥时代来了,而我还啥都不会。
思路
令 。
or 卷积一下即可。
对于 的情况:维护 ,加减只取最低位 的系数。
code
int n,a[1<<maxn],ans;
pii operator*(pii u,pii v){return {u.fi*v.fi%mod,u.se+v.se};}
pii operator/(pii u,pii v){return {u.fi*ksm(v.fi)%mod,u.se-v.se};}
pii operator+(pii u,pii v){
if(u.se<v.se)return u;
if(u.se>v.se)return v;
return {(u.fi+v.fi)%mod,u.se};}
pii operator-(pii u,pii v){
if(u.se<v.se)return u;
if(u.se>v.se)return v;
return {(u.fi+mod-v.fi)%mod,u.se};}
pii init(int v){
if(!v)return {1,1};
return {v,0};
}
int calc(pii p){return p.se?0:p.fi;}
pii f[1<<maxn],g[1<<maxn],h[1<<maxn];
void work(){
n=read();ans=0;
for(int i=0;i<(1<<n);i++)a[i]=read();
for(int i=0;i<(1<<n);i++)f[i]=init((a[i]+1)%mod),g[i]=init((2*a[i]+1)%mod);
for(int i=0;i<n;i++){
for(int s=0;s<(1<<n);s++)if(s&(1<<i)){
f[s^(1<<i)]=f[s^(1<<i)]*f[s];
g[s^(1<<i)]=g[s^(1<<i)]*g[s];
}
}
for(int s=0;s<(1<<n);s++){
h[s]={f[s].fi*((__builtin_popcount(s)&1)?mod-1:1)%mod*(1<<__builtin_popcount(s))%mod,f[s].se};
}
for(int i=0;i<n;i++){
for(int s=0;s<(1<<n);s++)if(s&(1<<i)){
h[s]=h[s]+h[s^(1<<i)];
}
}
for(int s=0;s<(1<<n);s++)h[s]=h[s]*h[s];
for(int i=0;i<n;i++){
for(int s=0;s<(1<<n);s++)if(s&(1<<i)){
h[s]=h[s]-h[s^(1<<i)];
}
}
for(int s=0;s<(1<<n);s++){
pii p=h[s]*g[s]/f[s]/f[s];
(ans+=calc(p)*ksm(2,mod-1-__builtin_popcount(s)))%=mod;
}
printf("%lld\n",ans);
}