LOJ#6433. 「PKUSC2018」最大前缀和 状压DP
思路比较自然.
开始的时候有一个地方糊涂了,后来想清楚就好了.
这里注意一个地方:
令 $f[S]$ 表示 $S$ 集合的所有排列中 sum(S) 为最大值的排列数.
然后转移 $f[S]$ 的时候要把新的元素放到序列开头,因为放到结尾的话前面的前缀可能非常小,导致到达不了结尾.
code:
#include <bits/stdc++.h> #define N 23 #define ll long long #define mod 998244353 #define setIO(s) freopen(s".in","r",stdin) using namespace std; int sum[1<<N],f[1<<N],g[1<<N],ge[1<<N],cn[N],a[N],n; inline int lowbit(int x) { return x&(-x); } int main() { // setIO("input"); for(int i=1;i<N;++i) cn[i]=1<<(i-1),ge[cn[i]]=i; scanf("%d",&n); for(int i=1;i<=n;++i) scanf("%d",&a[i]); g[0]=f[0]=1; for(int S=1;S<cn[n+1];++S) sum[S]=sum[S-lowbit(S)]+a[ge[lowbit(S)]]; for(int S=1;S<cn[n+1];++S) { int flag=0; for(int j=1;j<=n;++j) { if(S&cn[j]) { if(sum[S]<0) (g[S]+=g[S^cn[j]])%=mod; if(sum[S^cn[j]]>=0) (f[S]+=f[S^cn[j]])%=mod,flag=-1000; ++flag; } } if(flag==1) f[S]=1; } int ans=0; int tot=cn[n+1]-1; for(int S=1;S<cn[n+1];++S) { (ans+=(ll)((ll)f[S]*sum[S]%mod*g[tot-S]%mod+mod)%mod)%=mod; } printf("%d\n",ans); return 0; }