BZOJ5369 [Pkusc2018]最大字首和
阿新 • • 發佈:2018-12-05
題意
小C是一個演算法競賽愛好者,有一天小C遇到了一個非常難的問題:求一個序列的最大子段和。
但是小C並不會做這個題,於是小C決定把序列隨機打亂,然後取序列的最大字首和作為答案。
小C是一個非常有自知之明的人,他知道自己的演算法完全不對,所以並不關心正確率,他只關心求出的解的期望值,
現在請你幫他解決這個問題,由於答案可能非常複雜,所以你只需要輸出答案乘上n!後對998244353取模的值,顯然這是個整數。
注:最大字首和的定義:i∈[1,n],Sigma(aj)的最大值,其中1<=j<=i
\(n \leq 20\)
分析
乘上\(n!\),所謂期望其實就是每種最大字首和乘上方案數的乘積的和。
參照Boss.Pi的題解。
看資料範圍,考慮狀壓dp。注意到字首和的取值只有 \(2^n\) 種.
然後可以列舉每一個集合的元素當最大字首和 , 那麼這個集合的元素排列之後每一個字尾都必須大於 \(0\) , 且這個集合的補集排列之後必須保證每一個字首和都小於 \(0\).
那麼狀壓 DP 就行了 , 設 \(f[i]\) 表示集合 \(i\) 作為最大字首和且排列之後每個字尾都大於 \(0\) 的方案數 , \(g[i]\) 表示集合 \(i\) 中元素排列之後每個字首都小於 \(0\) 的方案數.
強制 \(f,g\) 必須在合法的時候才能轉移就行了.
時間複雜度\(O(n 2^n)\)
程式碼
#include<iostream> #include<cstdio> #include<cstdlib> #include<cmath> #include<set> #include<map> #include<queue> #include<stack> #include<algorithm> #include<bitset> #include<cassert> #include<ctime> #include<cstring> #define rg register #define il inline #define co const template<class T>il T read() { rg T data=0; rg int w=1; rg char ch=getchar(); while(!isdigit(ch)) { if(ch=='-') w=-1; ch=getchar(); } while(isdigit(ch)) { data=data*10+ch-'0'; ch=getchar(); } return data*w; } template<class T>T read(T&x) { return x=read<T>(); } using namespace std; typedef long long ll; co int N=22,mod=998244353; int n; int a[N]; int sum[1<<N],f[1<<N],g[1<<N]; il int add(int x,int y) { return (x+y)%mod; } il int mul(int x,int y) { return (ll)x*y%mod; } int main() { // freopen(".in","r",stdin); // freopen(".out","w",stdout); read(n); for(int i=0;i<n;++i) read(sum[1<<i]); #define lowbit(x) (x&-x) for(int i=0;i<(1<<n);++i) sum[i]=sum[i-lowbit(i)]+sum[lowbit(i)]; for(int i=0;i<n;++i) f[1<<i]=1,g[1<<i]=1; for(int i=0;i<(1<<n);++i) { if(sum[i]>0) { // edit 1: the big brace is important for(int j=0;j<n;++j) if(~i>>j&1) f[i|(1<<j)]=add(f[i|(1<<j)],f[i]); } else { for(int j=0;j<n;++j) if(~i>>j&1) g[i|(1<<j)]=add(g[i|(1<<j)],g[i]); } } g[0]=1; int ans=0; for(int i=0;i<(1<<n);++i) if(sum[((1<<n)-1)^i]<=0) ans=add(ans,mul(f[i],mul(sum[i],g[((1<<n)-1)^i]))); printf("%d",(ans+mod)%mod); return 0; }
Hint
大括號的問題,害得我交了23次。