【题解】P5369 [PKUSC2018]最大前缀和

我是个因为题意挂了一天的傻逼……

实际上这是道很水的状压 DP(???)


题目链接

P5369 [PKUSC2018]最大前缀和 - 洛谷

题意概述

给定一个长度为 \(n\) 的序列 \(a\),求这个序列的所有排列的最大前缀和之和 \(\bmod~ 998244353\) 的结果。

注意:是最大前缀和之和而不是方案数之和。

(我当时因为题目问的特别绕于是成功理解错题意 \(5h\))

思路分析

首先可以发现一个显然但是很关键的结论:

如果一个位置 \(k\) 可以成为最大前缀和(若有多个,则取最右端的位置),当且仅当 \(\sum \limits_{i=1}^k a_i >=0\) 且 \(\sum \limits_{i=k+1}^n a_i<0\)。

也就是说,我们现在只需要确定位置 \(\le k\) 有哪些数(前缀),\(>k\) 有哪些数(后缀)即可。

然后我们观察数据范围:\(1 \le n \le 20\)。自然而然可以考虑到状压。

定义 \(dp1_{sta}\) 表示选了 \(sta\) 这个状态的数作为前缀,剩下的数作为后缀的方案数;

定义 \(dp2_{sta}\) 表示选了 \(sta\) 这个状态的数作为后缀,剩下的数作为前缀的方案数。

其中 \(sta\) 表示每个数选了没选,若选,则二进制下这个数对应的这一位为 \(1\),反之为 \(0\)。

那么对于每一位 \(k\) 作为最大前缀和的位置时,每一种选择 \(sta|(1<<k)\) 作为前缀的情况(至于这里为什么是 \(sta|(1<<k)\) 而非 \(sta\),后面会有解释),对答案总的贡献就为:

\[dp1_{sta}\times dp2_{sta|(1<<k) \oplus ((1<<n)-1)} \times sum_{sta|(1<<k)} \]

解释:

  1. 我们在枚举 \(sta\) 时,要保证 \(sta\) 二进制下第 \(k\) 位为 \(0\)。

    之所以这样枚举,是因为我们每次枚举最大前缀和位置时,这一位已经确定了,所以如果我们直接让 \(sta\) 二进制下第 \(k\) 位为 \(1\),而此时的 \(dp1_{sta}\) 表示的状态中 \(k\) 这一位并不确定,所以可能会算重,所以我们要钦定 \(sta\) 二进制下第 \(k\) 位为 \(0\)。

  2. 一个数异或 \((1<<n)-1\) 的结果是将这个数二进制下 \(\le n\) 的位取反,而对于此题中的 \(sta|(1<<k)\) 一定是小于 \((1<<n)\) 的,所以就相当于将 \(sta\) 二进制下所有位取反,而取反后的结果就是对于每一个前缀 \(sta\) 作为后缀的状态。

  3. 根据乘法原理, \(dp1_{sta} \times dp2_{sta|(1<<k)}\) 的结果就是以 \(sta|(1<<k)\) 为前缀的方案数。那么乘上 \(sum_{sta|(1<<k)}\) 得到的结果就是对答案的贡献。

现在我们考虑如何转移。

假设一个状态 \(sta\) 二进制下有 \(t\) 个 \(1\),那么它一定可以由有 \(t-1\) 个 \(1\) 的状态转移得到。如果写成正推,那么有:

\[dp1_{sta|(1<<i)}=dp1_{sta|(1<<i)}+dp1_{sta};\\ dp2_{sta|(1<<i)}=dp2_{sta|(1<<i)}+dp2_{sta}; \]

最后我们要预处理出来每一个状态作为前缀时最大前缀和,具体做法:

对于每一个 \(sta\) 二进制下为 \(1\) 的位 \(i\) 都给 \(sum_{sta}\) 加上 \(a_i\) 即可。

然后我们就可以愉快的转移啦。

易错点

由于 \(a_i\) 可能为负,所以 \(sum\) 有可能为负,所以最后要对答案进行负数保护,即:(+mod)%mod。

代码实现

//luoguP5369
#include<cstdio>
#include<iostream>
#define int long long
using namespace std;
const int maxn=25;
const int mod=998244353;
int a[maxn],s[1<<maxn],dp1[1<<maxn],dp2[1<<maxn];
int n,ans;inline int read()
{int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}return x*f;
}signed main()
{n=read();for(int i=0;i<n;i++)a[i]=read();dp1[0]=dp2[0]=1;for(int sta=0;sta<(1<<n);sta++){for(int i=0;i<n;i++){if((sta>>i)&1)(s[sta]+=a[i])%=mod;}}for(int sta=0;sta<(1<<n);sta++){for(int i=0;i<n;i++){if((sta>>i)&1)continue;if(s[sta]+a[i]>=0)(dp1[sta|(1<<i)]+=dp1[sta])%=mod;else (dp2[sta|(1<<i)]+=dp2[sta])%=mod;}}for(int i=0;i<n;i++)//枚举前缀最大值的位置。 {for(int sta=0;sta<(1<<n);sta++){if((sta>>i)&1)continue;int nxt=((1<<n)-1)^(sta|(1<<i));(ans+=dp1[sta]*dp2[nxt]%mod*s[sta|(1<<i)]%mod)%=mod;}}cout<<(ans+mod)%mod<<'\n';return 0;
}

大概算是,复习(重开)状压 DP 后的第一题?

感谢阅读。

【题解】P5369 [PKUSC2018]最大前缀和(状压 DP)相关推荐

  1. 最短Hamilton路径(哈密顿图,状压dp)

    题目: 给定一张 n 个点的带权无向图,点从 0~n-1 标号,求起点 0 到终点 n-1 的最短Hamilton路径. Hamilton路径的定义是从 0 到 n-1 不重不漏地经过每个点恰好一次. ...

  2. AcWing327.玉米田(状压DP)题解

    Acwing.玉米田(状压DP) 题目传送门 题目描述 农夫约翰的土地由M*N个小方格组成,现在他要在土地里种植玉米. 非常遗憾,部分土地是不育的,无法种植. 而且,相邻的土地不能同时种植玉米,也就是 ...

  3. AcWing1064.骑士(状压DP)题解

    Acwing.骑士(状压DP) 题目传送门 题目描述 在 n×n 的棋盘上放 k 个国王,国王可攻击相邻的 8 个格子,求使它们无法互相攻击的方案总数. 输入格式 共一行,包含两个整数 n 和 k. ...

  4. 【BZOJ】1076 [SCOI2008]奖励关 期望DP+状压DP

    [题意]n种宝物,k关游戏,每关游戏给出一种宝物,可捡可不捡.每种宝物有一个价值(有负数).每个宝物有前提宝物列表,必须在前面的关卡取得列表宝物才能捡起这个宝物,求期望收益.k<=100,n&l ...

  5. Educational Codeforces Round 13 E. Another Sith Tournament 状压dp

    E. Another Sith Tournament 题目连接: http://www.codeforces.com/contest/678/problem/E Description The rul ...

  6. AtCoder AGC035D Add and Remove (状压DP)

    题目链接 https://atcoder.jp/contests/agc035/tasks/agc035_d 题解 想了两小时憋出来一个状压DP,发现人家怎么空间才十几MB,原来暴力就行了... 考虑 ...

  7. BZOJ 4042 Luogu P4757 [CERC2014]Parades (树形DP、状压DP)

    题目链接 (BZOJ) https://www.lydsy.com/JudgeOnline/problem.php?id=4042 (Luogu) https://www.luogu.org/prob ...

  8. BZOJ 2734 [HNOI2012]集合选数 (状压DP、时间复杂度分析)

    题目链接 https://www.lydsy.com/JudgeOnline/problem.php?id=2734 题解 嗯早就想写的题,昨天因为某些不可告人的原因(大雾)把这题写了,今天再来写题解 ...

  9. 状压dp之二之三 炮兵阵地/玉米田 By cellur925

    一.简单的状压dp 玉米田 题目描述 Farmer John has purchased a lush new rectangular pasture composed of M by N (1 ≤ ...

  10. [ NOIP提高组 2016]愤怒的小鸟(暴搜 + 状压DP)// [SNOI2017]一个简单的询问(莫队)

    一次性写两道题 T1:一个简单的询问 题目 题解 代码实现 T2:愤怒的小鸟 题目 暴搜题解 暴搜代码实现 状压DP题解 状压DP代码实现 T1:一个简单的询问 题目 给你一个长度为 N 的序列 ai ...

最新文章

  1. sd.js帮助您简化繁重的获取数据、存储数据(CRUD)骚操作(吐槽~在安卓9.0以下或者IOS10.X以下手机端H5页面不支持,在这两种情况下的系统只能使用ajax或者原生js请求后台数据)
  2. 孟宪会老师推荐的一部C#图解教程
  3. 计算字符串和文件的MD5值
  4. 网络流媒体协议 RTSP协议
  5. leetcode算法题--数字序列中某一位的数字
  6. 引起SQL数据库超时的问题分析及解决办法
  7. NDK android Error:Expected caller to ensure valid ABI: MIPS
  8. Android2.3.7源码结构分析
  9. VS.NET 2005 Beta2的稳定性太差了:(
  10. 成功解决ValueError: numpy.ufunc size changed, may indicate binary incompatibility. Expected 216 from C h
  11. Linux获取本机hostname函数,Linux下获得主机与域名-gethostbyname和gethostbyaddr
  12. iOS项目功能模块封装SDK使用总结
  13. imwrite函数 matlab_用matlab做一个脉动磁势分解的动画
  14. SQL Server:CASE WHEN OREN ELSE END =不支持OR
  15. [Django学习] Django基础(8)_富文本编辑器
  16. c# – 强制硬件加速渲染
  17. R语言使用rnorm函数生成正太分布数据、使用stem函数可视化茎叶图、茎叶图很直观的表现出数据的分布情况
  18. proxmox ve 中文社区_Proxmox VE 部署维护
  19. echart hightchart 区别
  20. 《0day安全-软件漏洞分析技术》实验笔记2

热门文章

  1. javascript 逻辑运算符 和 或 非
  2. 计算机管理能看到移动硬盘,无法识别移动硬盘并且不显示磁盘图标.
  3. 文件上传5-uploads靶场
  4. 中国新能源汽车行业十四五展望规划与投资决策建议报告2022版
  5. Linux基础必懂:eth0,eth1,eth2,lo是什么意思?
  6. Matlab画图技巧: 不需要敲代码的傻瓜式操作流程
  7. 半导体器件制造封装材料和生产工艺流程(图文介绍)
  8. java工作愿景_2018年年终总结以及来年目标愿景
  9. 水晶报表的宽度调整方法(设计器、代码调整、rpt文件属性)
  10. c语言求阶乘的两种算法(递归和循环)