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


    点此看题面

    大致题意: 对于一个序列,求全排列下最大前缀和之和。

    状压(DP)

    考虑如果单纯按照题目中对于最大前缀和的定义,则一个序列它的最大前缀和是不唯一的。

    为了方便统计,我们姑且规定,如果一个序列中存在多个最大前缀和,我们取最靠后的一个。

    由此我们想到,对于一个序列可以把它分为两部分([1,k])([k+1,n])满足:

    • ([1,k])([1,k])本身的最大前缀和。
    • ([k+1,n])内所有前缀和均小于(0)

    显然,由于([1,k])是其本身的最大前缀和,而其之后每一段前缀和都小于(0),因此它就是整个序列的最大前缀和。

    ([1,k])区间的点集为(i)(s_i)为点集(i)内数的和(注意,此处的和不取模,要开(long long)存储),(f_i)为点集(i)排列成的序列是其本身的最大前缀和的方案数,(g_i)为点集(i)排列成的序列所有前缀和均小于(0)的方案数(易发现,(f)(g)分别对应上面的两个条件)。

    则答案就是(sum s_icdot f_icdot g_{2^{n-1} xor i})(结合前文自行理解)。

    (DP)转移

    考虑(DP)如何转移。

    对于(f_i),我们可以枚举一个不在点集(i)中的点(j)

    如果把(j)放在点集(i)排列成的序列的最后面,显然不太好转移,也无法利用(f)本身的性质。

    但如果我们把(j)放在点集(i)排列成的序列的最前面,则只要(s_ige 0),显然有:

    • (a_jle a_j+s_i)
    • 对于除(a_j)外的其他前缀(sum),由于在(f_i)中满足(sumle s_i),所以(a_j+sumle a_j+s_i)必然满足。

    也就是说,在(s_ige 0)时,可以保证此时点集排列成的序列是其本身的最大前缀和。

    因此,(f_{i|2^{j-1}}+=f_i)

    对于(g_i),我们同样枚举一个不在点集(i)中的点(j)

    与之前不同,这次我们可以直接把点(j)放在点集(i)排列成的序列的最后面。

    因为在(g_i)中满足所有前缀和均小于(0),此时在序列最后面新添了一个点,并不会影响之前的前缀和。

    而新添出的这个前缀和,就是这个序列的和,即(s_{i|2^{j-1}})

    很显然,若要满足条件,当且仅当(s_{i|2^{j-1}}<0)

    也就是说,在(s_{i|2^{j-1}}<0)时,可以保证此时点集排列成的序列所有前缀和均小于(0)

    因此,(g_{i|2^{j-1}}+=g_i)

    代码

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 20
    #define X 998244353
    #define Inc(x,y) ((x+=(y))>=X&&(x-=X))
    using namespace std;
    int n,a[N+5],f[1<<N],g[1<<N];long long s[1<<N];
    int main()
    {
    	RI i,j,t,ans=0;for(scanf("%d",&n),i=1;i<=n;++i) scanf("%d",a+i);//读入
    	for(t=1<<n,i=0;i^t;++i) for(j=1;j<=n;++j) (i>>j-1)&1&&(s[i]+=a[j]);//预处理s[i]
    	for(f[0]=1,i=0;i^t;++i) for(j=1;j<=n;++j) !((i>>j-1)&1)&&s[i]>=0&&Inc(f[i|(1<<j-1)],f[i]);//DP转移f[i]
    	for(g[0]=1,i=0;i^t;++i) for(j=1;j<=n;++j) !((i>>j-1)&1)&&s[i|(1<<j-1)]<0&&Inc(g[i|(1<<j-1)],g[i]);//DP转移g[i]
    	for(i=0;i^t;++i) ans=((s[i]%X+X)%X*f[i]%X*g[(t-1)^i]+ans)%X;return printf("%d",ans),0;//统计答案
    }
    
  • 相关阅读:
    uni-app picker通用方法 多个picker公用一个bindPickerChange方法 通用的@change事件
    ElementUI Cascader 级联选择器 hover触发不好用以及图标不显示问题
    jquery 最简单的重置DIV内容,重置表单内容方法
    bootstrap table 表头与内容不对齐问题解决
    hbuilder mui html vue ul li 自定义循环赋值ID
    vue文件中提示Expected Boolean, got String
    hbuilder连接模拟器进行联调(逍遥模拟器,MuMu模拟器,夜神模拟器)
    网易mumu无法启动,只在任务栏有个图标
    pytest——pycharm中右击运行(run)没有问题,在terminal中运行pytest报错:E ModuleNotFoundError: No module named
    eclipse的TestNG运行不了——eclipse刚安装完TestNG,首次建立测试用例,但是一直运行出错的问题。
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/Luogu5369.html
Copyright © 2020-2023  润新知