题面:点击打开链接
题解:点击打开链接(来自一位大佬)
学到了几点:算sum[S]可以用lowbitO(2^n)求解
求最大前缀和其实考虑什么情况满足是最大前缀和即可
一段和为0时要用最小表示法去重,相同的前缀和只统计一次。
#include<bits/stdc++.h>
using namespace std;
#define maxn 1200000
#define lowbit(x) (x&(-x))
typedef long long ll;
const ll p = 998244353;
int n,a[50],sum[maxn],N,num[maxn];
ll f[maxn],g[maxn],ans;
void init(){
N = 1 << n;
/* for (int i = 1 ; i <= 20 ; i++){
cout<<i<<" "<<lowbit(i)<<endl;
}*/
for (int i = 0 ; i < N ; i++){
sum[i] = sum[i ^ lowbit(i)] + num[lowbit(i)];
}
}
inline void Add(ll &x,ll y){
x += y;
if ( x >= p ) x -= p;
}
int main(){
freopen("input.txt","r",stdin);
scanf("%d",&n);
for (int i = 0 ; i < n ; i++) scanf("%d",&a[i]) , num[1 << i] = a[i];
init();
f[0] = g[0] = 1;
for (register int i = 0 ; i < N ; i++) if ( !i || (f[i] && sum[i] > 0) ){
for (register int j = 0 ; j < n ; j++){
if ( !((i >> j) & 1) ){
Add(f[i | (1 << j)],f[i]);
}
}
}
for (register int i = 0 ; i < N ; i++) if ( g[i] ){
for (register int j = 0 ; j < n ; j++){
if ( !((i >> j) & 1) && (sum[i] + a[j] <= 0) ){
Add(g[i | (1 << j)],g[i]);
}
}
}
for (register int i = 1 ; i < N ; i++){
ans = (ans + f[i] * g[(N - 1) ^ i] % p * sum[i]) % p;
}
cout<<(ans % p + p) % p<<endl;
return 0;
}