Solution
s
u
m
s
sum_s
sums表示
s
s
s状态的所有数对应的和
设
f
s
f_s
fs表示状态为
s
s
s的最大前缀和的方案数
part1
f
s
∣
(
1
<
<
i
)
+
=
f
s
(
s
u
m
s
>
0
)
f_{s|(1<<i)}+=f_s(sum_s>0)
fs∣(1<<i)+=fs(sums>0)
考虑在
i
i
i这个点后面放一个集合
s
s
s,得到一个集合:
i
(
a
0
)
i(a_0)
i(a0)
a
1
a_1
a1
a
2
.
.
.
a
n
a_2...a_n
a2...an
s
u
m
s
>
0
sum_s>0
sums>0保证了
s
u
m
0...
n
>
s
u
m
0...0
sum_{0...n}>sum_{0...0}
sum0...n>sum0...0
因为
f
s
f_s
fs保证了对于任意的
i
≤
n
i≤n
i≤n,都有
s
u
m
1...
i
<
s
u
m
1...
n
sum_{1...i}<sum_{1...n}
sum1...i<sum1...n
所以
f
s
∣
(
1
<
<
i
)
f_{s|(1<<i)}
fs∣(1<<i)保证了对于任意的
i
≤
n
i≤n
i≤n,都有
s
u
m
0...
i
<
s
u
m
0...
n
sum_{0...i}<sum_{0...n}
sum0...i<sum0...n
part2
设
g
s
g_s
gs表示状态为
s
s
s的所有前缀都
≤
0
≤0
≤0的方案数
g
s
+
=
g
s
(
1
<
<
i
)
(
s
u
m
s
≤
0
)
g_s+=g_{s^(1<<i)}(sum_s≤0)
gs+=gs(1<<i)(sums≤0)
part3
a n s = ∑ s u m s f s g ( 1 < < n ) − 1 − s ans=\sum sum_sf_sg_{(1<<n)-1-s} 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);
}