这是个什么集合DP啊…

想过枚举断点但是不会处理接下来的问题了…

我好菜啊

题目描述

小 C 是一个算法竞赛爱好者,有一天小 C 遇到了一个非常难的问题:求一个序列的最大子段和。

但是小 C 并不会做这个题,于是小 C 决定把序列随机打乱,然后取序列的最大前缀和作为答案。

小 C 是一个非常有自知之明的人,他知道自己的算法完全不对,所以并不关心正确率,他只关心求出的解的期望值,现在请你帮他解决这个问题,由于答案可能非常复杂,所以你只需要输出答案乘上 \(n!\) 后对 \(998244353\) 取模的值,显然这是个整数。

注:最大前缀和的定义:\(\forall i \in [1,n],\sum_{j=1}^{i}a_j\) 的最大值。

输入格式

第一行一个正整数 \(n\),表示序列长度。

第二行 \(n\) 个数,表示原序列 \(a[1..n]\),第 \(i\) 个数表示 \(a[i]\) 。

输出格式

输出一个非负整数,表示答案。

样例输入

2
-1 2

样例输出

3

数据范围与约定

对于 \(10\%\) 的数据,有 \(1\leq n\leq 9\)。

对于 \(40\%\) 的数据,有 \(1\leq n\leq 15\)。

另有 \(10\%\) 的数据,满足 \(a\) 中最多只有一个负数。

另有 \(10\%\) 的数据,满足 \(|a[i]|\leq 2∣\)。

对于 \(100\%\) 的数据,满足 \(1\leq n\leq 20,\sum_{i=1}^{n}|a[i]|\leq 10^9\)。

题解

看到数据范围,这道题显然不是 \(O(n!)\),我们要把一个全排列转化为一个部分排列,对于部分排列统计一些答案,从而做到 \(O(2^n)\) 级别。

如果我们单独考虑对最大前缀和贡献,那么针对每个元素,我们无法判断它到底在最大前缀和中出现了几次。

这时我们需要研究最大前缀和的意义和等价条件。(被分割线隔开的主要是证明)


下文中 \(sum[l,r]\) 指 \(\sum_{i=l}^r a_i\),\(sum[S]\) 指 \(\sum_{i\in S}a_i\)。

对于一个序列,如果 \(sum[1,k]=\max_{1\le i\le n} \{sum[1,i]\}​\) ,那么说明对于任意 \(j>k​\),都不存在 \(sum[1,j]>sum[1,k]​\)。由此推得不存在 \(sum[k+1,j]>0​\)。

同时,对于任意 \(1\le j<k​\),都不存在 \(sum[1,j]>sum[1,k]​\),说明 \(sum[1,k]​\) 是 \(a[1,k]​\) 的最大前缀和。

这时我们用归纳法来推导它的性质。

已知 \(sum[i,k]​\) 是 \(a[i,k]​\) 的最大前缀和。

因此对于任意 \(i\le j\le k​\),已经满足 \(sum[i,j]\le sum[i,k]​\)。

设 \(S_1=\{sum[i,i],sum[i,i+1],\cdots,sum[i,k]\}​\),那么 \(\forall x\in S_1​\) 都有 \(x\le sum[i,k]​\)。

设 \(S_2=\{sum[i-1,i-1],sum[i-1,i],\cdots,sum[i-1,k]\}​\),显然 \(|S_1|+1=|S_2|​\)。

而 \(S_2​\) 的后面 \(|S_2|-1​\) 项都是 \(S_1​\) 的相应项 \(+a_{i-1}​\),因此仍然满足 \(x\le sum[i,k]+a_{i-1}=sum[i-1,k]​\)。

只需要第一项 \(sum[i-1,i-1]​\) 满足 \(\le sum[i-1,k]​\) 的条件就可以了。

所以 \(sum[1,k]\) 是最大前缀和的条件是(此处认为区间左右端点可以相等)

  • \(\forall i\in[1,k],a_i\le sum[i,k]\),
  • \(\forall i\in(k,n],sum[k+1,i]<0\)。

后者要求小于 \(0\) 而不是小于等于,原因在于当 \(i\in(k,n]\) 中多次出现 \(sum[k+1,i]=0\) 的情况时,进行了冗余的计算。实际上这一步计算会在后面那些元素被枚举到自己位置时算出来并做出贡献。


考虑用 \(f[S]\) 表示选出 \(S\) 这个集合中的元素,他们的全排列中满足条件 1 的排列个数。

排列可以用二进制集合枚举表示出来。

我们枚举每个集合 \(S\) 和元素 \(i\)。当 \(i\notin S\) 时我们就把 \(i\) 插到 \(S\) 的最前面,此时认为集合 \(S\) 无序。如果满足 \(a_i\le a_i+sum[S]\),则令 \(f[S]=f[S]+f[S\cup\{i\}]\)。

为什么说把 \(i\) 插到 \(S\) 前面呢?因为对第一个式子的归纳意义,后面的一定满足条件,只需要考虑新插入进来的元素是否满足。

那这样实际上我们也是遍历了所有排列。因为 \(S\) 的构造过程比较有趣:

设 \(S=\tt 1111\),它可以从 \(T_1=\mathtt{0111},T_2=\mathtt{1011},T_3=\mathtt{1101},T_4=\mathtt{1110}\) 转移过来。

我们特殊考虑 \(T_1\),假定 \(T_1\) 已经表示了 \(\tt 0111\) 的全排列,那么从 \(T_1\) 转移到 \(S\) 的就只有第一个元素在 \(S\) 的第一个位置这种情况了。

而第一个元素不在 \(S\) 的第一个位置时,一定在 \(T_2,T_3,T_4\) 枚举到了。

所以 \(S\) 遍历了 \(\tt 1111\) 的全排列。

同理,用 \(g[S]\) 表示选出 \(S\) 这个集合的元素,这些元素的全排列满足条件 \(2​\) 的个数。

最后我们也不需要枚举断点,只需要枚举集合,毕竟集合代表了所有的排列。

答案就是

\[\sum_{S\in U}sum[S]\times f[S]\times\complement_US,\ U=\{a_1,a_2,\cdots,a_n\}
\]

以上除了式子的判断条件,均在对 \(998,244,353\) 取模意义下进行。

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

Code:

#include<cstdio>
#include<cstring>
#define p 998244353
int a[20],f[1<<20],g[1<<20],sum[1<<20];
int Plus(int x,int y){return x+y>=p?x+y-p:x+y;}
int Mul(int x,int y){return 1ll*x*y%p;}
int main()
{
int n,U;
scanf("%d",&n);
U=(1<<n)-1;
for(int i=0;i<n;++i)
{
scanf("%d",&a[i]);
f[1<<i]=1;
if(a[i]<0)
g[1<<i]=1;
}
for(int i=1;i<=U;++i)
for(int j=0;j<n;++j)
if(i&(1<<j))
sum[i]+=a[j];
for(int i=1;i<=U;++i)
for(int j=0;j<n;++j)
if(!(i&(1<<j)))
{
if(sum[i]+a[j]>=a[j])
f[i|(1<<j)]=Plus(f[i|(1<<j)],f[i]);
if(sum[i]+a[j]<0)
g[i|(1<<j)]=Plus(g[i|(1<<j)],g[i]);
}
g[0]=1;
int ans=0;
for(int i=1;i<=U;++i)
ans=Plus(ans,Mul(Mul(p+sum[i],f[i]),g[U^i]));
printf("%d\n",ans);
return 0;
}

loj 6433 「PKUSC2018」最大前缀和 题解【DP】【枚举】【二进制】【排列组合】的更多相关文章

  1. loj#6433. 「PKUSC2018」最大前缀和(状压dp)

    传送门 今天\(PKUWC\)试机的题 看着边上的大佬们一个个\(A\)穿咱还是不会-- 我们考虑枚举最大前缀和,如果一个前缀\(1\)到\(p\)是最大前缀和,那么\(p\)后面的所有前缀和都要小于 ...

  2. LOJ 6433 「PKUSC2018」最大前缀和——状压DP

    题目:https://loj.ac/problem/6433 想到一个方案中没有被选的后缀满足 “该后缀的任一前缀和 <=0 ”. 于是令 dp[ S ] 表示选了点集 S ,满足任一前缀和 & ...

  3. Loj#6433「PKUSC2018」最大前缀和(状态压缩DP)

    题面 Loj 题解 先转化题意,其实这题在乘了\(n!\)以后就变成了全排列中的最大前缀和的和(有点拗口).\(n\leq20\),考虑状压\(DP\) 考虑一个最大前缀和\(\sum\limits_ ...

  4. Loj 6433. 「PKUSC2018」最大前缀和 (状压dp)

    题面 Loj 题解 感觉挺难的啊- 状压\(dp\) 首先,有一个性质 对于一个序列的最大前缀和\(\sum_{i=1}^{p} A[i]\) 显然对于每个\(\sum_{i=p+1}^{x}A[i] ...

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

    原文链接https://www.cnblogs.com/zhouzhendong/p/LOJ6433.html 题解 枚举一个集合 S ,表示最大前缀和中包含的元素集为 S ,然后求出有多少个排列是这 ...

  6. [LOJ #6433]「PKUSC2018」最大前缀和

    题目大意:给你一个$n(n\leqslant20)$项的数列$A$,设重排后的数列为$A'$,令$pre_p=\sum\limits_{i=1}^pA'_i$,求$max\{pre_i\}$的期望,乘 ...

  7. 【LOJ】#6433. 「PKUSC2018」最大前缀和

    题解 神仙的状压啊QAQ 设一个\(f[S]\)表示数字的集合为\(S\)时\(sum[S]\)为前缀最大值的方案数 \(g[S]\)表示数字集合为\(S\)时所有前缀和都小于等于0的方案数 答案就是 ...

  8. LOJ #6436. 「PKUSC2018」神仙的游戏(字符串+NTT)

    题面 LOJ #6436. 「PKUSC2018」神仙的游戏 题解 参考 yyb 的口中的长郡最强选手 租酥雨大佬的博客 ... 一开始以为 通配符匹配 就是类似于 BZOJ 4259: 残缺的字符串 ...

  9. LOJ #6435. 「PKUSC2018」星际穿越(倍增)

    题面 LOJ#6435. 「PKUSC2018」星际穿越 题解 参考了 这位大佬的博客 这道题好恶心啊qwq~~ 首先一定要认真阅读题目 !! 注意 \(l_i<r_i<x_i\) 这个条 ...

随机推荐

  1. [SoapUI]怎样配置SoapUI运行的不同环境,并在Jenkins上面通过命令调用不用的环境

    配置SoapUI运行的不同环境 Groovy 脚本来控制environment 在Jenkins上面通过命令调用不用的环境 http://www.soapui.org/Test-Automation/ ...

  2. 修复PlatformToolsets丢失问题(为VS2013以上版本安装VC90,VC100编译器)

    前段时间测试VS2017的IDE时不小心弄丢了 MSBuild\Microsoft.Cpp\v4.0\Platforms\Win32\PlatformToolsets 下的VC90以及VC100的编译 ...

  3. (转)【经验之谈】Git使用之Windows环境下配置

    原文地址:http://www.cnblogs.com/xishuai/p/3590434.html 前言 安装 配置 关于git使用的几个问题 后记 关于代码托管,以前用过vss和svn,看博客或论 ...

  4. HRBUST1200 装修 2017-03-06 15:41 94人阅读 评论(0) 收藏

    装修 hero为了能顺利娶princess ,花了血本,买了个房子,现在决定装修.房子的长度为n米,宽度为3米,现在我们有2种地砖,规格分别是1米×1米,2米×2米,如果要为该教室铺设地砖,请问有几种 ...

  5. FTP服务器的搭建与安全配置

    FTP可以说是Internet上使用非常广泛的一种通讯协议了.它工作在OSI模型的第7层,是TCP/IP的一种具体应用.FTP采用基于TCP的可靠连接:监听21端口来等待控制连接请求,当连接建立后,采 ...

  6. POJ 3977 Subset(折半枚举+二分)

    SubsetTime Limit: 30000MS        Memory Limit: 65536KTotal Submissions: 6754        Accepted: 1277 D ...

  7. [毕业设计][期末作业]二手闲置小程序 免费信息发布系统功能源码(小程序+php后台管理)

    最近做了一个小程序,主要是二手闲置免费信息发布系统的功能,里面包括了登录,发布商品,商品管理,违规投诉,canva商品海报生成,分享等一些基础的功能,可以说代码都是自己辛辛苦苦写出来的.可作为毕业设计 ...

  8. linux gitlab-ctl reconfigure报错问题修复 502

    Running handlers: There was an error running gitlab-ctl reconfigure: bash[migrate gitlab-rails datab ...

  9. C# 实用小类

    /// <summary> /// 汉字转换拼音 /// </summary> /// <param name="PinYin"></pa ...

  10. c# .NET RSA结合AES加密服务端和客户端请求数据

    这几天空闲时间就想研究一下加密,环境是web程序,通过js请求后台返回数据,我想做的事js在发送请求前将数据加密,服务端收到后解密,待服务端处理完请求后,将处理结果加密返回给客户端,客户端在解密,于是 ...