1. 程式人生 > >[PKUSC2018]最大前綴和

[PKUSC2018]最大前綴和

() ++ clu math tdi lin int() 題目 期望值

[PKUSC2018]最大前綴和

題目大意:

\(n(n\le20)\)個數\(A_i(|A_i|\le10^9)\)。求這\(n\)個數在隨機打亂後最大前綴和的期望值與\(n!\)的積在模\(998244353\)意義下的值。其中最大前綴和的定義為\(\forall i\in[1,n]\sum_{j=1}^iA_j\)的最大值。

思路:

考慮一個分界點\(p\),使得\(\sum A_{1\sim p}\)為最大前綴和,那麽顯然\(p\)之後的所有前綴和均\(<0\),否則就存在可以替換\(p\)的方案使得前綴和更大。

\(sum[i]\)表示子集\(i\)的數值和,\(f[i]\)表示最大前綴和為\(sum[i]\)

的方案數,\(g[i]\)表示任意前綴和均為負的方案數。\(f[i]\)\(g[i]\)均可以通過動態規劃求得。最後答案即為\(\sum sum[S]\times f[S]\times g[\overline S]\)。時間復雜度\(\mathcal O(2^nn)\)

源代碼:

#include<cstdio>
#include<cctype>
typedef long long int64;
inline int getint() {
    register char ch;
    register bool neg=false;
    while(!isdigit(ch=getchar())) neg|=ch=='-'
; register int x=ch^'0'; while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); return neg?-x:x; } const int N=20,mod=998244353; int a[N],f[1<<N],g[1<<N]; int64 sum[1<<N]; int main() { const int n=getint(),u=(1<<n)-1; g[0]=1; for
(register int i=0;i<n;i++) { f[1<<i]=1; a[i]=getint(); for(register int s=0;s<1<<n;s++) { if(s&(1<<i)) sum[s]+=a[i]; } } for(register int s=1;s<1<<n;s++) { if(sum[s]>0) { for(register int i=0;i<n;i++) { if(!(s&(1<<i))) { (f[s|(1<<i)]+=f[s])%=mod; } } } else { for(register int i=0;i<n;i++) { if(s&(1<<i)) { (g[s]+=g[s^(1<<i)])%=mod; } } } } int ans=0; for(register int i=1;i<1<<n;i++) { (ans+=(int64)sum[i]*f[i]%mod*g[u^i]%mod)%=mod; } printf("%d\n",(ans+mod)%mod); return 0; }

[PKUSC2018]最大前綴和