Solution
sums表示 s状态的所有数对应的和
设 fs表示状态为 s的最大前缀和的方案数
part1
fs∣(1<<i)+=fs(sums>0)
考虑在 i这个点后面放一个集合 s,得到一个集合:
i(a0) a1 a2...an
sums>0保证了 sum0...n>sum0...0
因为 fs保证了对于任意的 i≤n,都有 sum1...i<sum1...n
所以 fs∣(1<<i)保证了对于任意的 i≤n,都有 sum0...i<sum0...n
part2
设 gs表示状态为 s的所有前缀都 ≤0的方案数
gs+=gs(1<<i)(sums≤0)
part3
ans=∑sumsfsg(1<<n)−1−s
Code
#include<cstdio>
const int N=1<<20,M=998244353;
int n,i,s,ans,f[N],g[N],sum[N],a[N],st;
inline void ADD(int &x,int y){x+=y;if(x>=M)x-=M;}
int main(){
scanf("%d",&n);
for (i=0;i<n;i++) scanf("%d",&a[1<<i]),f[1<<i]=1;
st=(1<<n)-1;
for (s=0;s<=st;s++) sum[s]=sum[s^(s&-s)]+a[s&-s];
for (s=0;s<=st;s++)
if (f[s] && sum[s]>0)
for (i=st^s;i;i^=i&-i) ADD(f[s|(i&-i)],f[s]);
g[0]=1;
for (s=1;s<=st;s++)
if (sum[s]<=0)
for (i=s;i;i^=i&-i) ADD(g[s],g[s^(i&-i)]);
for (s=0;s<=st;s++) ans=(1ll*sum[s]*f[s]%M*g[st^s]+ans)%M;
printf("%d",(ans+M)%M);
}