LOJ:https://loj.ac/problem/6433c++
注意到最大前缀要知足什么性质,假设序列\(a[1..n]\)的最大前缀是\(s_x\),那么显然要知足全部\(x\)结尾的后缀和都为正,且全部\(x\)开头的前缀和都为负,\(0\)的状况不影响。git
有了这个转化以后就好作了,直接状压,设\(g[s]\)为选了\(s\)这些数,能构成多少种序列,使得全部前缀都为负或\(0\)。ui
转移直接暴力枚举当前哪个填最后一位就行了。spa
设\(f[s]\)表示选了\(s\)这些数,能构成多少种序列使得除了整个序列之外全部后缀都为正,转移和上面相似。code
而后统计答案直接乘起来就行了。get
复杂度\(O(2^n\cdot n)\)。it
#include<bits/stdc++.h> using namespace std; void read(int &x) { x=0;int f=1;char ch=getchar(); for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f; for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f; } void print(int x) { if(x<0) putchar('-'),x=-x; if(!x) return ;print(x/10),putchar(x%10+48); } void write(int x) {if(!x) putchar('0');else print(x);putchar('\n');} #define lf double #define ll long long #define pii pair<int,int > #define vec vector<int > #define pb push_back #define mp make_pair #define fr first #define sc second #define FOR(i,l,r) for(int i=l,i##_r=r;i<=i##_r;i++) const int maxn = (1<<20)+10; const int inf = 1e9; const lf eps = 1e-8; const int mod = 998244353; int add(int x,int y) {return x+y>=mod?x+y-mod:x+y;} int del(int x,int y) {return x-y<0?x-y+mod:x-y;} int mul(int x,int y) {return 1ll*x*y-1ll*x*y/mod*mod;} int s[maxn],f[maxn],g[maxn],a[22],n,all,ans; int main() { read(n);FOR(i,0,n-1) read(a[i]);all=1<<n,all--; FOR(i,1,all) s[i]=a[__builtin_ctz(i)]+s[i^(i&-i)];g[0]=1; FOR(i,1,all) if(s[i]<=0) FOR(j,0,n-1) if((i>>j)&1) g[i]=add(g[i],g[i^(1<<j)]); FOR(i,0,n-1) f[1<<i]=1; FOR(i,1,all) { if(s[i]>0) FOR(j,0,n-1) if(!((i>>j)&1)) f[i^(1<<j)]=add(f[i^(1<<j)],f[i]); ans=add(ans,mul(s[i]%mod+mod,mul(f[i],g[all-i]))); }write(ans); return 0; }