【PKUSC2018】【loj6433】最大前缀和 状压dp

这题吼啊...

然而还是想了$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] \times f[i] \times g[2^n-1-i] $

当前缀和<0时

$ans2=\sum_{j=0}^{n=1} \sum_{i=0} (a[j]+s[i])\times f[i]\times g[2^n-1-i-2^j]\ \ \ [(2^j\ and\ i=0)∩s[i]<0∩s[i]>-a[j]]$

最终所求答案即$ans1+ans2$。

然后就完结了。

时间复杂度为$O(n \times 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     

猜你喜欢

转载自www.cnblogs.com/xiefengze1/p/9170243.html
今日推荐