Loj#6433「PKUSC2018」最大前缀和(状态压缩DP)
题面
题解
先转化题意,其实这题在乘了$n!$以后就变成了全排列中的最大前缀和的和(有点拗口)。$n\leq20$,考虑状压$DP$
考虑一个最大前缀和$\sum\limits_{i=1}^pa_i$,这个位置$p$是最大前缀和的右界当且仅当对于$\forall r>p$有:$\sum\limits_{i=p+1}^ra_i\leq0$
设$sum_i$表示二进制状态$i$的代数和,方便转移
设$g_i$表示选了子集$i$后有多少种排列使得所有的前缀和都$<0$,于是有(从下转移而来):
$$
g[i] += g[i \oplus (1 << j)]\ (sum[i]\leq0,sum[i\oplus(1<<j)]\leq0)
$$
设$f_i$表示选了子集$i$后有多少种排列使得最大前缀和$=sum_i$,于是有(向上转移):
$$
f[i \ | \ (1 << j)]+=f[i]\ (sum[i]>0)
$$
则最后答案就是($m\oplus i$表示$i$的补集):
$$
ans=\sum_{i\in S}sum_i\times f_i \times g_{m\oplus i}
$$
#include <cstdio>
#include <cstring>
#include <algorithm>
using std::min; using std::max;
using std::swap; using std::sort;
typedef long long ll;
template<typename T>
void read(T &x) {
int flag = 1; x = 0; char ch = getchar();
while(ch < '0' || ch > '9') { if(ch == '-') flag = -flag; ch = getchar(); }
while(ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar(); x *= flag;
}
const int N = 22, P = 998244353;
int n, m, a[1 << N], f[1 << N], g[1 << N], sum[1 << N], ret;
int lb(int x) { return x & -x; }
int main () {
read(n), m = (1 << n) - 1;
for(int i = 0; i < n; ++i) read(a[1 << i]);
for(int i = 0; i <= m; ++i)
sum[i] = sum[i ^ lb(i)] + a[lb(i)];
g[0] = 1;
for(int i = 0; i < n; ++i) f[1 << i] = 1;
for(int i = 0; i <= m; ++i) {
if(sum[i] <= 0) {
for(int j = 0; j < n; ++j)
if((1 << j) & i && sum[i ^ (1 << j)] <= 0)
(g[i] += g[i ^ (1 << j)]) %= P;
}
}
for(int i = 0; i <= m; ++i) {
if(sum[i] > 0) {
for(int j = 0; j < n; ++j)
if(!((1 << j) & i)) (f[i | (1 << j)] += f[i]) %= P;
}
(ret += 1ll * (sum[i] + P) % P * f[i] % P * g[m ^ i] % P) %= P;
}
printf("%d\n", ret);
return 0;
}
Loj#6433「PKUSC2018」最大前缀和(状态压缩DP)的更多相关文章
- LOJ 6433 「PKUSC2018」最大前缀和——状压DP
题目:https://loj.ac/problem/6433 想到一个方案中没有被选的后缀满足 “该后缀的任一前缀和 <=0 ”. 于是令 dp[ S ] 表示选了点集 S ,满足任一前缀和 & ...
- LOJ#6433. 「PKUSC2018」最大前缀和 状压dp
原文链接https://www.cnblogs.com/zhouzhendong/p/LOJ6433.html 题解 枚举一个集合 S ,表示最大前缀和中包含的元素集为 S ,然后求出有多少个排列是这 ...
- loj 6433 「PKUSC2018」最大前缀和 题解【DP】【枚举】【二进制】【排列组合】
这是个什么集合DP啊- 想过枚举断点但是不会处理接下来的问题了- 我好菜啊 题目描述 小 C 是一个算法竞赛爱好者,有一天小 C 遇到了一个非常难的问题:求一个序列的最大子段和. 但是小 C 并不会做 ...
- Loj 6433. 「PKUSC2018」最大前缀和 (状压dp)
题面 Loj 题解 感觉挺难的啊- 状压\(dp\) 首先,有一个性质 对于一个序列的最大前缀和\(\sum_{i=1}^{p} A[i]\) 显然对于每个\(\sum_{i=p+1}^{x}A[i] ...
- loj#6433. 「PKUSC2018」最大前缀和(状压dp)
传送门 今天\(PKUWC\)试机的题 看着边上的大佬们一个个\(A\)穿咱还是不会-- 我们考虑枚举最大前缀和,如果一个前缀\(1\)到\(p\)是最大前缀和,那么\(p\)后面的所有前缀和都要小于 ...
- [LOJ #6433]「PKUSC2018」最大前缀和
题目大意:给你一个$n(n\leqslant20)$项的数列$A$,设重排后的数列为$A'$,令$pre_p=\sum\limits_{i=1}^pA'_i$,求$max\{pre_i\}$的期望,乘 ...
- 【LOJ】#6433. 「PKUSC2018」最大前缀和
题解 神仙的状压啊QAQ 设一个\(f[S]\)表示数字的集合为\(S\)时\(sum[S]\)为前缀最大值的方案数 \(g[S]\)表示数字集合为\(S\)时所有前缀和都小于等于0的方案数 答案就是 ...
- LOJ #6436. 「PKUSC2018」神仙的游戏(字符串+NTT)
题面 LOJ #6436. 「PKUSC2018」神仙的游戏 题解 参考 yyb 的口中的长郡最强选手 租酥雨大佬的博客 ... 一开始以为 通配符匹配 就是类似于 BZOJ 4259: 残缺的字符串 ...
- LOJ #6435. 「PKUSC2018」星际穿越(倍增)
题面 LOJ#6435. 「PKUSC2018」星际穿越 题解 参考了 这位大佬的博客 这道题好恶心啊qwq~~ 首先一定要认真阅读题目 !! 注意 \(l_i<r_i<x_i\) 这个条 ...
随机推荐
- java 7修改文件权限
Full control over file attributes is available in Java 7, as part of the "new" New IO faci ...
- 【BZOJ】1574: [Usaco2009 Jan]地震损坏Damage
[算法]搜索 [题意]给定无向图,现在可能有一些点已经被删除,只给出信息是c个点不能到达结点1,求最少的不能到达结点1的个数(含已删除点). [题解] 真是一道奥妙重重的题目. 每个点不能到达结点1, ...
- bzoj 1856 组合
这道题有些类似卡特兰数的其中一种证明,总方案数是c(n+m,n),点(m,n)对应y=x-1对称点为(n+1,m-1),所以答案为c(n+m,n)-c(n+m,n+1). 反思:开始坐标轴画错了,结果 ...
- 利用certutil.exe 传文件
certutill.exe 在Windows 7 及其之后的所有Windows Server和Workstation版本均预装 1. Encode file: certutil -encode kk. ...
- Android使用TextView实现跑马灯效果(自定义控件)
对于一个长的TetxView 折行显示是一个很好的办法,另一种方法就是跑马灯显示(单行滚动) 1.折行显示的长TextView <LinearLayout xmlns:android=" ...
- Vue组件-组件的注册
注册组件 全局组件 注册组件就是利用Vue.component()方法,先传入一个自定义组件的名字,然后传入这个组件的配置. Vue.component('my-component', { templ ...
- 在linux程序里面,知道一个函数地址,改函数是属于某个动态库的,怎么样得到这个动态库的全【转】
转自:http://www.360doc.com/content/17/1012/11/48326749_694292472.shtml 另外dl_iterate_phdr可以查到当前进程所装在的所有 ...
- linux编程之信号
信号(signal)机制是UNIX系统中最为古老的进程之间的通信机制,它用在一个或多个进程之间传递异步信号,信号可以由各种异步事件产生,如: 键盘中断等等,在Linux 的shell 中,也可以使用信 ...
- python基础===8道基础知识题
本文转自微信公众号: 2018-03-12 leoxin 菜鸟学Python 原文地址:http://mp.weixin.qq.com/s/JJSDv5YJOZ9e3hn28zWIsQ NO.1 Py ...
- python基础===输入必须为数字的检验的另一种方法
print("[+]welcome to python3") while True: num = input("please input a num:") if ...