[PKUSC2018]最大前綴和(DP)
阿新 • • 發佈:2018-06-10
集合 大於 怎麽 amp font turn tdi ont 序列
題意:求一個序列隨機打亂後最大前綴和的期望。
考場上發現不管怎麽設狀態都寫不出來,實際上只要稍微轉換一下就好了。
一個前綴[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 }
[PKUSC2018]最大前綴和(DP)