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;
}

浙公网安备 33010602011771号