P5369
[PKUSC2018]最大前缀和
状压 DP。
期望值乘上
于是最后要求的答案就是所有排列的最大前缀和的和。
然后定义两个状态
然后两个状态可以组成答案:
简单来说,就是
然后就是关于
因为插入的数的位置很影响
那么此时,
时间复杂度
代码:
#include<iostream>
#include<cstdio>
#define ll long long
using namespace std;
const ll N=22,mo=998244353;
ll n,ans;
ll sum[1<<N],f[1<<N],g[1<<N];
inline ll read() {
ll ret=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-') f=-f;ch=getchar();}
while(ch>='0'&&ch<='9') {ret=(ret<<3)+(ret<<1)+ch-'0';ch=getchar();}
return ret*f;
}
void write(ll x) {
static char buf[22];static ll len=-1;
if(x>=0) {
do{buf[++len]=x%10+48;x/=10;}while(x);
}
else {
putchar('-');
do{buf[++len]=-(x%10)+48;x/=10;}while(x);
}
while(len>=0) putchar(buf[len--]);
}
int main() {
n=read();
for(ll i=1;i<=n;i++) {
sum[1<<(i-1)]=read();f[1<<(i-1)]=1;
}
for(ll i=0;i<(1<<n);i++) {
sum[i]=sum[i^(i&-i)]+sum[i&-i];
}
g[0]=1;
for(ll i=0;i<(1<<n);i++) {
if(sum[i]>=0) {
for(ll j=1;j<=n;j++) {
if(!((i>>(j-1))&1)) {
f[i|(1<<(j-1))]=(f[i|(1<<(j-1))]+f[i])%mo;
}
}
}
else {
for(ll j=1;j<=n;j++) {
if((i>>(j-1))&1) {
g[i]=(g[i]+g[i^(1<<(j-1))])%mo;
}
}
}
}
for(ll i=0;i<(1<<n);i++) {
ans=(ans+((((sum[i]%mo)*f[i]+mo)%mo)*g[((1<<n)-1)^i]+mo)%mo+mo)%mo;
}
write(ans);
return 0;
}