这题吼啊...
然而还是想了$2h$,写了$1h$。
我们发现一个性质:若一个序列$p$能作为前缀和,那么在序列$p$中,包含序列$p$最后一个数的所有子序列必然都是非负的。
那么,我们
令$f[i]$表示状态$i$中所有数字全部作为前缀和的方案数。
令$g[i]$表示状态$i$中所有数字所组合成的任意排列中,前缀和永远为负数的方案数。
令$s[i]$表示状态$i$中所有数字之和。
ps:若i的第j个二进制位为$1$,则表示状态$i$中,选择了数字$a_j$。($a$序列的下表为$0$到$n-1$)
通过冷静分析,不难得出:
$s[i]$很好求
$f[i]=sum_{(2^j and i)=2^j∩s[i-2^j]+a[j]≥0} f[i-2^j]$
$g[i]=sum_{(2^j and i)=2^j∩s[i-2^j]+a[j]<0} g[i-2^j]$
显然$f[0]=g[0]=1$。
统计答案时,分前缀和$≥0$,前缀和$<0$两类讨论。
当前缀和$≥0$时
$ans1=sum_{i=1}^{2^n-1} s[i] imes f[i] imes g[2^n-1-i] $
当前缀和<0时
$ans2=sum_{j=0}^{n=1} sum_{i=0} (a[j]+s[i]) imes f[i] imes g[2^n-1-i-2^j] [(2^j and i=0)∩s[i]<0∩s[i]>-a[j]]$
最终所求答案即$ans1+ans2$。
然后就完结了。
时间复杂度为$O(n imes 2^n)$。
1 #include<bits/stdc++.h> 2 #define M 20 3 #define L long long 4 #define MOD 998244353 5 using namespace std; 6 7 L f[1<<M]={0},g[1<<M]={0},a[M]={0},he[1<<M]={0}; 8 9 int main(){ 10 int n,m; scanf("%d",&n); m=1<<n; 11 for(int i=0;i<n;i++) cin>>a[i]; 12 for(int i=0;i<m;i++) 13 for(int j=0;j<n;j++) 14 if(i&(1<<j)) he[i]+=a[j]; 15 f[0]=1; 16 for(int i=1;i<m;i++){ 17 for(int j=0;j<n;j++) 18 if((i&(1<<j))&&he[i^(1<<j)]+a[j]>=0){ 19 f[i]=(f[i]+f[i^(1<<j)])%MOD; 20 } 21 } 22 for(int i=0;i<n;i++) a[i]=-a[i]; 23 for(int i=0;i<m;i++) he[i]=-he[i]; 24 g[0]=1; 25 for(int i=1;i<m;i++){ 26 for(int j=0;j<n;j++) 27 if((i&(1<<j))&&he[i^(1<<j)]+a[j]>0){ 28 g[i]=(g[i]+g[i^(1<<j)])%MOD; 29 } 30 } 31 for(int i=0;i<n;i++) a[i]=-a[i]; 32 for(int i=0;i<m;i++) he[i]=-he[i]; 33 L ans=0; 34 for(int j=0;j<n;j++) if(a[j]<0){ 35 //f[1<<j]=1; 36 for(int i=0;i<m;i++) 37 if((i&(1<<j))==0){ 38 if(he[i]<0||he[i]>-a[j]) continue; 39 int hh=(m-1)^i^(1<<j); 40 ans=(ans+(a[j]+he[i])*f[i]%MOD*g[hh]%MOD+MOD)%MOD; 41 } 42 } 43 for(int i=0;i<m;i++) 44 ans=(ans+f[i]*he[i]%MOD*g[(m-1)^i]%MOD+MOD)%MOD; 45 cout<<ans<<endl; 46 } 47