标签:zoj algorithm 答案 name ... 时间 style ret can
题意:求一个序列随机打乱后最大前缀和的期望。
考场上发现不管怎么设状态都写不出来,实际上只要稍微转换一下就好了。
一个前缀[1..k]是最大前缀,当且仅当前面的所有后缀[k-1,k],[k-2,k],...,[1,k]都大于0,后面的所有前缀[k+1,k+2],[k+1,k+3],...,[k+1,n]全部不大于0。
于是设f[S]表示S集合满足所有后缀大于0的排列数,g[S]表示S前缀不大于0的排列数,直接转移,最后答案就是所有集合(空集除外)的f乘上补集的g。
不卡时BZOJ时间榜与码长榜 rank 1。
1 #include<cstdio> 2 #include<algorithm> 3 #define rep(i,l,r) for (int i=(l),_=(r); i<=_; i++) 4 using namespace std; 5 6 const int N=1048577,mod=998244353; 7 int n,ans,a[N],cnt[N],f[N],g[N],ll[N]; 8 inline void up(int &x,int y){ x+=y; if (x>=mod) x-=mod; } 9 10 int main(){ 11 scanf("%d",&n); int S=(1<<n)-1; g[0]=1; 12 rep(i,0,n-1) scanf("%d",&a[1<<i]); 13 rep(s,1,S){ 14 int t=s&-s; cnt[s]=cnt[s^t]+a[t]; 15 if (!(s^t)) { f[s]=1; g[s]=(a[t]<=0); continue; } 16 for (int p=s; p; p=p^t,t=p&-p){ 17 if (cnt[s^t]>0) up(f[s],f[s^t]); 18 if (cnt[s]<=0) up(g[s],g[s^t]); 19 } 20 } 21 rep(s,1,S) ans=(ans+1ll*f[s]*g[S^s]%mod*cnt[s])%mod; 22 printf("%d\n",(ans+mod)%mod); 23 return 0; 24 }
标签:zoj algorithm 答案 name ... 时间 style ret can
原文地址:https://www.cnblogs.com/HocRiser/p/9162247.html