LOJ#6433. 「PKUSC2018」最大前缀和 状压dp

原文链接https://www.cnblogs.com/zhouzhendong/p/LOJ6433.html

题解

枚举一个集合 S ,表示最大前缀和中包含的元素集为 S ,然后求出有多少个排列是这样的。

对于左边和右边分别考虑,我们可以发现:

左边:每一个后缀和都 >=0

右边:每一个前缀和都 <0

然后就只需要用两个 dp 分别求出每一个集合的元素的排列中分别满足上述条件的方案数即可。

注意一下题目要求最大前缀和非空。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
int read(){
    int x=0,f=1;
    char ch=getchar();
    while (!isdigit(ch)&&ch!='-')
        ch=getchar();
    if (ch=='-')
        f=0,ch=getchar();
    while (isdigit(ch))
        x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    return f?x:-x;
}
const int N=20,mod=998244353;
int n,a[N];
int Log[1<<N],sum[1<<N],dp1[1<<N],dp2[1<<N];
void Add(int &x,int y){
    if ((x+=y)>=mod)
        x-=mod;
}
int main(){
    n=read();
    for (int i=0;i<n;i++)
        a[i]=read();
    for (int i=2;i<(1<<n);i++)
        Log[i]=Log[i>>1]+1;
    for (int i=1;i<(1<<n);i++)
        sum[i]=sum[i^(i&-i)]+a[Log[i&-i]];
    dp1[0]=1;
    for (int i=0;i<n;i++)
        dp2[1<<i]=1;
    for (int i=1;i<(1<<n);i++)
        for (int j=0;j<n;j++)
            if (i>>j&1){
                if (sum[i]<0)
                    Add(dp1[i],dp1[i^(1<<j)]);
                if (sum[i]-a[j]>=0)
                    Add(dp2[i],dp2[i^(1<<j)]);
            }
    int ans=0,base=(1<<n)-1;
    for (int i=1;i<(1<<n);i++)
        ans=(1LL*sum[i]*dp2[i]%mod*dp1[i^base]+ans)%mod;
    ans=(ans+mod)%mod;
    printf("%d",ans);
    return 0;
}

  

posted @   zzd233  阅读(200)  评论(0编辑  收藏  举报
编辑推荐:
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· PostgreSQL 和 SQL Server 在统计信息维护中的关键差异
· C++代码改造为UTF-8编码问题的总结
· DeepSeek 解答了困扰我五年的技术问题
· 为什么说在企业级应用开发中,后端往往是效率杀手?
阅读排行:
· Deepseek官网太卡,教你白嫖阿里云的Deepseek-R1满血版
· 2分钟学会 DeepSeek API,竟然比官方更好用!
· .NET 使用 DeepSeek R1 开发智能 AI 客户端
· DeepSeek本地性能调优
· 一文掌握DeepSeek本地部署+Page Assist浏览器插件+C#接口调用+局域网访问!全攻略

点击右上角即可分享
微信分享提示