[PKUSC2018]最大前綴和
阿新 • • 發佈:2018-06-08
() ++ clu math tdi lin int() 題目 期望值 的方案數,\(g[i]\)表示任意前綴和均為負的方案數。\(f[i]\)和\(g[i]\)均可以通過動態規劃求得。最後答案即為\(\sum sum[S]\times f[S]\times g[\overline S]\)。時間復雜度\(\mathcal O(2^nn)\)。
[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]\)
源代碼:
#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]最大前綴和