这是个什么集合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]\) 。

输出格式

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

样例输入

  1. 2
  2. -1 2

样例输出

  1. 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:

  1. #include<cstdio>
  2. #include<cstring>
  3. #define p 998244353
  4. int a[20],f[1<<20],g[1<<20],sum[1<<20];
  5. int Plus(int x,int y){return x+y>=p?x+y-p:x+y;}
  6. int Mul(int x,int y){return 1ll*x*y%p;}
  7. int main()
  8. {
  9. int n,U;
  10. scanf("%d",&n);
  11. U=(1<<n)-1;
  12. for(int i=0;i<n;++i)
  13. {
  14. scanf("%d",&a[i]);
  15. f[1<<i]=1;
  16. if(a[i]<0)
  17. g[1<<i]=1;
  18. }
  19. for(int i=1;i<=U;++i)
  20. for(int j=0;j<n;++j)
  21. if(i&(1<<j))
  22. sum[i]+=a[j];
  23. for(int i=1;i<=U;++i)
  24. for(int j=0;j<n;++j)
  25. if(!(i&(1<<j)))
  26. {
  27. if(sum[i]+a[j]>=a[j])
  28. f[i|(1<<j)]=Plus(f[i|(1<<j)],f[i]);
  29. if(sum[i]+a[j]<0)
  30. g[i|(1<<j)]=Plus(g[i|(1<<j)],g[i]);
  31. }
  32. g[0]=1;
  33. int ans=0;
  34. for(int i=1;i<=U;++i)
  35. ans=Plus(ans,Mul(Mul(p+sum[i],f[i]),g[U^i]));
  36. printf("%d\n",ans);
  37. return 0;
  38. }

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. Java程序设计17——多线程-Part-B

    5 改变线程优先级 每个线程执行都具有一定的优先级,优先级高的线程获得较多的执行机会,而优先级低的线程则获得较少的执行机会. 每个线程默认的优先级都与创建它的父线程具有相同的优先级,在默认情况下,ma ...

  2. GPS坐标转换为百度地图坐标

    /** * GPS坐标转换为百度地图坐标 * 需要引入javabase64.jar 和json的一些包 * */ public class Gps2BaiDu { public static void ...

  3. 一起做RGB-D SLAM(7) (完结篇)

    第七讲 添加回环检测 2016.11 更新 把原文的SIFT替换成了ORB,这样你可以在没有nonfree模块下使用本程序了. 回环检测的阈值作出了相应的调整. 请以现在的github上源码为准. 简 ...

  4. Overflow与块状格式上下文

  5. 如何用Python实现常见机器学习算法-2

    二.逻辑回归 1.代价函数 可以将上式综合起来为: 其中: 为什么不用线性回归的代价函数表示呢?因为线性回归的代价函数可能是非凸的,对于分类问题,使用梯度下降很难得到最小值,上面的代价函数是凸函数的图 ...

  6. Monokai风格的EditPlus配色方案

    EditPlus的配置文件editplus_u.ini,该文件默认在:系统盘:\Users\用户名\AppData\Roaming\EditPlus目录中.将其中的内容替换为如下即可: [Option ...

  7. Robotframework-Appium 之常用API(一)

    上一遍隨筆(https://www.cnblogs.com/cnkemi/p/9639809.html)用Python + Robotframework + Appium對Android app小試牛 ...

  8. handsontable 概述

    很像excel的jquery插件.关于它的中文资料不多,自己只能看看英文的了.记录如下: developer guide //主要是这八部分数据绑定:renderer, afterchange, se ...

  9. TSQL--如何突破PRINT的8000大限

    相信很多DBA都喜欢干的一件事就是拼SQL语句,我也不例外,但是PRINT只能打印4000的Unicode string或8000的Non-unicode string, 这个蛋疼的限制会导致过长的s ...

  10. 不错的Django博客

    https://blog.csdn.net/chengqiuming/article/category/8453874 杜塞的个人网站 https://www.dusaiphoto.com/ 追梦人物 ...