题意

小C是一个算法竞赛爱好者,有一天小C遇到了一个非常难的问题:求一个序列的最大子段和。
但是小C并不会做这个题,于是小C决定把序列随机打乱,然后取序列的最大前缀和作为答案。
小C是一个非常有自知之明的人,他知道自己的算法完全不对,所以并不关心正确率,他只关心求出的解的期望值,
现在请你帮他解决这个问题,由于答案可能非常复杂,所以你只需要输出答案乘上n!后对998244353取模的值,显然这是个整数。
注:最大前缀和的定义:i∈[1,n],Sigma(aj)的最大值,其中1<=j<=i

\(n \leq 20\)

分析

乘上\(n!\),所谓期望其实就是每种最大前缀和乘上方案数的乘积的和。

参照Boss.Pi的题解。

看数据范围,考虑状压dp。注意到前缀和的取值只有 \(2^n\) 种.

然后可以枚举每一个集合的元素当最大前缀和 , 那么这个集合的元素排列之后每一个后缀都必须大于 \(0\) , 且这个集合的补集排列之后必须保证每一个前缀和都小于 \(0\).

那么状压 DP 就行了 , 设 \(f[i]\) 表示集合 \(i\) 作为最大前缀和且排列之后每个后缀都大于 \(0\) 的方案数 , \(g[i]\) 表示集合 \(i\) 中元素排列之后每个前缀都小于 \(0\) 的方案数.

强制 \(f,g\) 必须在合法的时候才能转移就行了.

时间复杂度\(O(n 2^n)\)

关于转移的问题

就算f加上j转移到了不合法的状态,以后也不会用到。

所以是对的。

代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<algorithm>
#include<bitset>
#include<cassert>
#include<ctime>
#include<cstring>
#define rg register
#define il inline
#define co const
template<class T>il T read()
{
    rg T data=0;
    rg int w=1;
    rg char ch=getchar();
    while(!isdigit(ch))
    {
        if(ch=='-')
            w=-1;
        ch=getchar();
    }
    while(isdigit(ch))
    {
        data=data*10+ch-'0';
        ch=getchar();
    }
    return data*w;
}
template<class T>T read(T&x)
{
    return x=read<T>();
}
using namespace std;
typedef long long ll;

co int N=22,mod=998244353;
int n;
int a[N];
int sum[1<<N],f[1<<N],g[1<<N];

il int add(int x,int y)
{
    return (x+y)%mod;
}

il int mul(int x,int y)
{
    return (ll)x*y%mod;
}

int main()
{
//  freopen(".in","r",stdin);
//  freopen(".out","w",stdout);
    read(n);
    for(int i=0;i<n;++i)
        read(sum[1<<i]);
#define lowbit(x) (x&-x)
    for(int i=0;i<(1<<n);++i)
        sum[i]=sum[i-lowbit(i)]+sum[lowbit(i)];
    for(int i=0;i<n;++i)
        f[1<<i]=1,g[1<<i]=1;
    for(int i=0;i<(1<<n);++i)
    {
        if(sum[i]>0)
        { // edit 1: the big brace is important
            for(int j=0;j<n;++j)
                if(~i>>j&1)
                    f[i|(1<<j)]=add(f[i|(1<<j)],f[i]);
        }
        else
        {
            for(int j=0;j<n;++j)
                if(~i>>j&1)
                    g[i|(1<<j)]=add(g[i|(1<<j)],g[i]);
        }
    }
    g[0]=1;
    int ans=0;
    for(int i=0;i<(1<<n);++i)
        if(sum[((1<<n)-1)^i]<=0)
            ans=add(ans,mul(f[i],mul(sum[i],g[((1<<n)-1)^i])));
    printf("%d",(ans+mod)%mod);
    return 0;
}

Hint

大括号的问题,害得我交了23次。

BZOJ5369 [Pkusc2018]最大前缀和的更多相关文章

  1. BZOJ5369:[PKUSC2018]最大前缀和(状压DP)

    Description 小C是一个算法竞赛爱好者,有一天小C遇到了一个非常难的问题:求一个序列的最大子段和. 但是小C并不会做这个题,于是小C决定把序列随机打乱,然后取序列的最大前缀和作为答案. 小C ...

  2. [PKUSC2018]最大前缀和

    [PKUSC2018]最大前缀和 题目大意: 有\(n(n\le20)\)个数\(A_i(|A_i|\le10^9)\).求这\(n\)个数在随机打乱后最大前缀和的期望值与\(n!\)的积在模\(99 ...

  3. BZOJ_5369_[Pkusc2018]最大前缀和_状压DP

    BZOJ_5369_[Pkusc2018]最大前缀和_状压DP Description 小C是一个算法竞赛爱好者,有一天小C遇到了一个非常难的问题:求一个序列的最大子段和. 但是小C并不会做这个题,于 ...

  4. [PKUSC2018]最大前缀和——状压DP

    题目链接: [PKUSC2018]最大前缀和 设$f[S]$表示二进制状态为$S$的序列,任意前缀和都小于等于$0$的方案数. 设$g[S]$表示二进制状态为$S$的序列是整个序列的最大前缀和的方案数 ...

  5. LOJ6433 [PKUSC2018] 最大前缀和 【状压DP】

    题目分析: 容易想到若集合$S$为前缀时,$S$外的所有元素的排列的前缀是小于$0$的,DP可以做到,令排列前缀个数小于0的是g[S]. 令f[S]表示$S$是前缀,转移可以通过在前面插入元素完成. ...

  6. bzoj 5369: [Pkusc2018]最大前缀和

    Description 小C是一个算法竞赛爱好者,有一天小C遇到了一个非常难的问题:求一个序列的最大子段和. 但是小C并不会做这个题,于是小C决定把序列随机打乱,然后取序列的最大前缀和作为答案. 小C ...

  7. [PKUSC2018]最大前缀和(DP)

    题意:求一个序列随机打乱后最大前缀和的期望. 考场上发现不管怎么设状态都写不出来,实际上只要稍微转换一下就好了. 一个前缀[1..k]是最大前缀,当且仅当前面的所有后缀[k-1,k],[k-2,k], ...

  8. P5369 [PKUSC2018]最大前缀和

    状态压缩 P5369 题意:求所有排列下的最大前缀和之和 一步转化: 求最大前缀和的前缀由数集S组成的方案数, 统计答案时直接乘上sum(S)即可 考虑最大前缀和的性质: 设最大前缀和为sum[i] ...

  9. 【洛谷5369】[PKUSC2018] 最大前缀和(状压DP)

    点此看题面 大致题意: 对于一个序列,求全排列下最大前缀和之和. 状压\(DP\) 考虑如果单纯按照题目中对于最大前缀和的定义,则一个序列它的最大前缀和是不唯一的. 为了方便统计,我们姑且规定,如果一 ...

随机推荐

  1. idea 2018注册码

    原文:https://blog.csdn.net/zhw0596/article/details/81394870 (最新的看后面!!!    转载的请附上原文链接   搜索不易!)百度的,上一个没用 ...

  2. Java的优势

    Java是一种跨平台,适合于分布式计算环境的面向对象编程语言. 具体来说,它具有如下特性: 简单性.面向对象.分布式.解释型.可靠.安全.平台无关.可移植.高性能.多线程.动态性等. 下面我们将重点介 ...

  3. Android面试三之Service

    Service是什么 Service(服务)是一个没有用户界面的在后台运行执行耗时操作的应用组件.其他应用组件能够启动Service,并且当用户切换到另外的应用场景,Service将持续在后台运行.另 ...

  4. Spring Boot配置ContextPath【从零开始学Spring Boot】

    Spring boot默认是/ ,这样直接通过http://ip:port/就可以访问到index页面,如果要修改为http://ip:port/path/ 访问的话,那么需要在Application ...

  5. C# RedisRateLimiter

    public class RedisRateLimiter { private static Logger LOG = LogManager.GetLogger("redis-limiter ...

  6. 008PHP基础知识——运算符(一)

    <?php /** * 运算符(一) */ /*PHP中的运算符: * 1.算术运算符: * 2.递增/递减运算符 * 3.比较运算符 * 4.逻辑运算符 * 5.位运算符 * 6.其他运算符 ...

  7. Java 进阶7 并发优化 1 并行程序的设计模式

       本章重点介绍的是基于 Java并行程序开发以及优化的方法,对于多核的 CPU,传统的串行程序已经很好的发回了 CPU性能,此时如果想进一步提高程序的性能,就应该使用多线程并行的方式挖掘 CPU的 ...

  8. CF 914

    照例看A 然后A了 看B 似乎博弈一下就可以了 然后看C 似乎是DP 然后看了room woc似乎有黑红名 赶紧hack 然后没有人有问题 思考为什么 突然看到房间有15hack... 好吧我做D 然 ...

  9. zuul 性能分析

    引用几篇博客, 后续整理自己心得 Zuul 性能测试 https://blog.csdn.net/u013815546/article/details/69669165 VisualVM 使用 htt ...

  10. Redis的集群安装以及rehash重新迁移教程指南

    1. Redis的cluster集群 在官方文档Cluster Spec中,作者详细介绍了Redis集群为什么要设计成现在的样子.最核心的目标有三个: 性能:这是Redis赖以生存的看家本领,增加集群 ...