www.cnblogs.com/shaokele/
bzoj5369: [PKUSC2018]最大前缀和##
Time Limit: 20 Sec
Memory Limit: 512 MB
题目地址: bzoj5369: [PKUSC2018]最大前缀和
题目大意: 全排列,求每次最大前缀之和####
题解:
考试时没A 哭唧唧
其实就是一个状态压缩
具体看代码
AC代码
#include <cstdio>
using namespace std;
const int N=21,mo=998244353;
int n;
int a[N],f[1<<N],g[1<<N];
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
//f[S] 表示取S的状态使前缀>0的方案数
//g[S] 表示取S的状态使前缀<=0的方案数
for(int i=1;i<(1<<n);i++){
int now=0,s=0;
for(int j=1;j<=n;j++)
if(i&(1<<(j-1)))
now+=a[j],s++;
if(s==1)f[i]=1;
else
for(int j=1;j<=n;j++)
if((i&(1<<(j-1))) && now-a[j]>0)
f[i]=(f[i]+f[i^(1<<(j-1))])%mo; //当前i的情况可以从f[i^(1<<(j-1))]推过来
}
g[0]=1;
for(int i=1;i<(1<<n);i++){
int now=0,s=0;
for(int j=1;j<=n;j++)
if(i&(1<<(j-1)))
now+=a[j],s++;
if(now>0)g[i]=0;
else{
if(s==1){
g[i]=1;
continue;
}
for(int j=1;j<=n;j++)
if(i&(1<<(j-1)))
g[i]=(g[i]+g[i^(1<<(j-1))])%mo; //同 f
}
}
int ans=0;
for(int i=1;i<(1<<n);i++){
int now=0,del=(1ll*f[i]*g[(1<<n)-1-i])%mo; //now:值 del:方案数
for(int j=1;j<=n;j++)
if(i&(1<<(j-1)))now=(now+a[j]+mo)%mo;
now=(1ll*now*del)%mo;
ans=(ans+now)%mo;
}
printf("%d
",ans);
return 0;
}