P5369-[PKUSC2018]最大前缀和【状压dp】
生活随笔
收集整理的這篇文章主要介紹了
P5369-[PKUSC2018]最大前缀和【状压dp】
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
正題
題目鏈接:https://www.luogu.com.cn/problem/P5369
題目大意
一個數(shù)列aaa的權(quán)值定義為max{∑i=1kai}(k∈[1,n])max\{\sum_{i=1}^ka_i\}(k\in[1,n])max{∑i=1k?ai?}(k∈[1,n])
給出nnn個數(shù)字,求它們所有排列的權(quán)值和
1≤n≤201\leq n\leq 201≤n≤20
解題思路
設(shè)si,fi,gis_i,f_i,g_isi?,fi?,gi?分別表示集合iii的權(quán)值和,集合iii的所有排列中最大前綴和為sis_isi?的方案數(shù),集合iii的所有排列中的最大前綴和為負(fù)的方案數(shù)。那么答案就是
∑i=02n?1fisig2n?1?i\sum_{i=0}^{2^n-1} f_is_ig_{2^n-1-i}i=0∑2n?1?fi?si?g2n?1?i?
sis_isi?很好求。gig_igi?的話我們只轉(zhuǎn)移si<0s_i<0si?<0的就可以了,fif_ifi?的話我們考慮每次在前面插入一個數(shù),那么只要原來的是最大前綴和,那么插入之后也一定是。
時間復(fù)雜度O(2nn)O(2^nn)O(2nn)
code
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=21,P=998244353; int n,a[N],lg[1<<N],s[1<<N],f[1<<N],g[1<<N],ans; int main() {scanf("%d",&n);for(int i=0;i<n;i++)scanf("%d",&a[i]);for(int i=0;i<n;i++)lg[1<<i]=i;int MS=(1<<n);f[0]=g[0]=1;for(int i=1;i<MS;i++){int p=i&-i;s[i]=(s[i-p]+a[lg[p]])%P;}for(int i=0;i<MS;i++){if(s[i]<0)continue;for(int j=0;j<n;j++){if(i&(1<<j))continue;(f[i|(1<<j)]+=f[i])%=P;}}for(int i=0;i<MS;i++){for(int j=0;j<n;j++){if(i&(1<<j))continue;int z=i|(1<<j);if(s[z]<0)(g[z]+=g[i])%=P;}}for(int i=0;i<MS;i++)(ans+=1ll*f[i]*g[MS-1-i]%P*s[i]%P)%=P;printf("%d\n",(ans+P)%P);return 0; }總結(jié)
以上是生活随笔為你收集整理的P5369-[PKUSC2018]最大前缀和【状压dp】的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 4000左右台式机配置推荐(4000台式
- 下一篇: Wannafly挑战赛23F-计数【原根