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

这题吼啊...

然而还是想了2h,写了1h

我们发现一个性质:若一个序列p能作为前缀和,那么在序列p中,包含序列p最后一个数的所有子序列必然都是非负的。

那么,我们

f[i]表示状态i中所有数字全部作为前缀和的方案数。

g[i]表示状态i中所有数字所组合成的任意排列中,前缀和永远为负数的方案数。

s[i]表示状态i中所有数字之和。

ps:若i的第j个二进制位为1,则表示状态i中,选择了数字aj。(a序列的下表为0n1

 

通过冷静分析,不难得出:

s[i]很好求

f[i]=(2j and i)=2js[i2j]+a[j]0f[i2j]

g[i]=(2j and i)=2js[i2j]+a[j]<0g[i2j]

显然f[0]=g[0]=1

 

统计答案时,分前缀和0,前缀和<0两类讨论。

当前缀和0

ans1=2n1i=1s[i]×f[i]×g[2n1i]

当前缀和<0时

ans2=n=1j=0i=0(a[j]+s[i])×f[i]×g[2n1i2j]   [(2j and i=0)s[i]<0s[i]>a[j]]

最终所求答案即ans1+ans2

然后就完结了。

时间复杂度为O(n×2n)

 

复制代码
 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     
复制代码

 

posted @   AlphaInf  阅读(304)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
点击右上角即可分享
微信分享提示