BZOJ4036: [HAOI2015]按位或
阿新 • • 發佈:2019-01-01
BZOJ4036: [HAOI2015]按位或
https://lydsy.com/JudgeOnline/problem.php?id=4036
分析:
- 設\(f_{i,s}\)表示\(i\)次後數字是\(s\)的概率。
- 那麼答案就是\(\sum\limits_{i=1}^{\infty}i\times (f_{i,all}-f_{i-1,all})\)。
- \(=\infty -\sum\limits_{i=1}^{\infty}f_{i,all}\)。
- 考慮逐項計算\(f\),可以發現每次計算是一個或卷積的形式。
- 即如果設\(g_{i,S}=\sum\limits_{T\subseteq S}f_{i,S}\)
- 於是上面的式子可以用\(g\)來改寫,這裡就懶得寫了。
- 求出\(g\)後,由於答案只需要\(all\)這一項, 這裡選擇用子集反演的方式直接求答案,能優化掉一個\(fwt\)。
程式碼:
#include <cstdio> #include <cstring> #include <algorithm> #define N 1050000 typedef double f2; int K,n,cnt[N]; f2 p[N]; void fwt(f2 *a,int len,int flg) { int i,j,k,t; for(k=2;k<=len;k<<=1)for(t=k>>1,i=0;i<len;i+=k)for(j=i;j<i+t;j++) { if(flg==1) a[j+t]+=a[j]; else a[j+t]-=a[j]; } } int main() { scanf("%d",&K); n=(1<<K)-1; int i,mk=0; for(i=0;i<=n;i++) cnt[i]=cnt[i>>1]+(i&1),scanf("%lf",&p[i]),p[i]>1e-6?(mk|=i):0; if(mk!=n) {puts("INF"); return 0;} fwt(p,n+1,1); f2 ans=0; for(i=0;i<n;i++) { if((K-cnt[i])&1) ans-=1/(1-p[i]); else ans+=1/(1-p[i]); } printf("%.8f\n",-ans); } #include <cstdio> #include <cstring> #include <algorithm> #include <vector> using namespace std; typedef long long ll; #define N 2100000 #define mod 998244353 ll f[22][N],g[22][N],A[N],sum[N]; int ea[550],eb[550]; int n,m,p,w[22],CNT[N]; int head[22],to[550],nxt[550],cnt,Q[22],vis[22],du[22]; inline void add(int u,int v) { to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt; } ll qp(ll x,ll y) { ll re=1; for(;y;y>>=1,x=x*x%mod) if(y&1) re=re*x%mod; return re; } bool check(int s) { int i; for(i=1;i<=n;i++) du[i]=head[i]=vis[i]=0; cnt=0; for(i=1;i<=m;i++) { if((s&(1<<(ea[i]-1))) && (s&(1<<(eb[i]-1)))) add(ea[i],eb[i]),add(eb[i],ea[i]),du[ea[i]]++,du[eb[i]]++; } for(i=1;i<=n;i++) if(du[i]&1) return 0; int l=0,r=0; for(i=1;i<=n;i++) if(s&(1<<(i-1))) { Q[r++]=i; vis[i]=1; break; } while(l<r) { int x=Q[l++]; for(i=head[x];i;i=nxt[i]) if(!vis[to[i]]) { vis[to[i]]=1; Q[r++]=to[i]; } } return r==CNT[s]; } void fort(ll *a,int len,int flg) { int i,j,k,t; for(k=2;k<=len;k<<=1) for(t=k>>1,i=0;i<len;i+=k) for(j=i;j<i+t;j++) { if(flg==1) a[j+t]=(a[j+t]+a[j])%mod; else a[j+t]=(a[j+t]-a[j])%mod; } } int main() { scanf("%d%d%d",&n,&m,&p); int i,j,k; for(i=1;i<=m;i++) scanf("%d%d",&ea[i],&eb[i]); for(i=1;i<=n;i++) scanf("%d",&w[i]); int mask=(1<<n)-1; for(i=1;i<=mask;i++) { CNT[i]=CNT[i>>1]+(i&1); ll re=0; for(j=1;j<=n;j++) if(i&(1<<(j-1))) { re+=w[j]; } g[CNT[i]][i]=qp(re,p); sum[i]=qp(g[CNT[i]][i],mod-2); if(check(i)) g[CNT[i]][i]=0; } for(i=1;i<=n;i++) fort(g[i],1<<n,1); for(i=0;i<=mask;i++) f[0][i]=1; for(i=1;i<=n;i++) { for(j=1;j<=i;j++) { for(k=0;k<=mask;k++) { A[k]=(A[k]+g[j][k]*f[i-j][k]); } } for(k=0;k<=mask;k++) A[k]%=mod; fort(A,1<<n,-1); for(k=0;k<=mask;k++) { f[i][k]=A[k]*sum[k]%mod; A[k]=0; } if(i<n) fort(f[i],1<<n,1); } printf("%lld\n",(f[n][mask]+mod)%mod); }