[NOI2019]序列(模拟费用流)
题意:
有两个长度为n的序列,要求从每个序列中选k个,并且满足至少有l个位置都被选,问总和最大是多少。
\(1\leq l\leq k\leq n\leq 2*10^5\)。
首先,记录当前考虑到的位置i,第一个选的数量a, 第二个选的数量b,都被选的数量c,可以做到\(O(n^4)\),
卡常后能过\(n\leq 150\),有40分。
考虑正解:首先,看到这个范围,可以认为正解一定是贪心。
先看下\(n\leq 2000\),这个是网络流的范围。我们可以先建出费用流,然后再变为模拟费用流,即贪心。
从源点向第一个序列连边,第二个序列向汇点连边。
然后,我们发现至少有l个位置都被选不太容易表示,因为左面向对应的右面连的边是分开的,无法放到一起考虑下限。
换一种思路:至少有l个位置都被选,就是剩的位置不超过\(k-l\)。
所以,我们可以这样建图:
1、从源点向第一个序列连边,第二个序列向汇点连边。
2、对应位置连流量为1的边。
3、第一个序列都向点a连边,点b向第二个序列连边。a到b连容量\(k-l\)的边。
求出流量为k的最大费用流即可。这样据说有64分。
考虑模拟费用流优化:
首先,记录s表示a到b的剩余流量。
1、若\(s>0\),则可以通过a到b的边增广,即从两个序列中各选一个最大数,并把s减去1。
2、可以直接走左右的对应连边增广,即选一个左右相加最大的位置。
3、可以走\(S->x->x'->b->y'->T\),走\(x'->b\)的前提是x在第二个序列中被选。
即在第一个序列中选一个第二个序列中被选的位置,再选一个第二个序列中没被选的作为y。
4、与3对称,即在第二个序列中选一个第一个序列中被选的位置,再选一个第一个序列中没被选的。
因为是最长路增广,所以在2,3,4中选最大的。以上操作可以用5个优先队列完成。
然而,我们发现过不去样例。
其实,算法是对的,但我们少了一些情况(特判):
首先,还可以走\(S->x->x'->b->a->y->y'->T\)。(情况5)
就是在第二个序列中选一个第一个序列中被选的位置,再在第一个序列中选一个第二个序列中被选的位置,
因为退了a到b的流,要把s加1。
在1中,若选的两个位置相同,则不用减s。若选的位置在另一序列中已被选,则为情况3或4,不用减s。
若选的位置在另一序列中都已被选,则为情况5,把s加1。
在3,4中,可能会转移到情况5,此时要把s加1。
加上这些后就能过了,实现时要注意细节。
代码:
#include <stdio.h>
#include <queue>
using namespace std;
struct SJd {
int z, i;
SJd() {}
SJd(int Z, int I) {
z = Z;i = I;
}
};
bool operator < (const SJd a, const SJd b) {
return a.z < b.z;
}
#define prio priority_queue < SJd >
#define ll long long
int sa[200010],sb[200010],ba[200010],bb[200010];
prio pa,pb,pc,pd,pe,em;
inline int read() {
char ch;
while ((ch = getchar()) < '0' || ch > '9');
int rt = ch - '0';
while ((ch = getchar()) >= '0' && ch <= '9') rt = (rt << 3) + (rt << 1) + ch - '0';
return rt;
}
int main() {
int T;
scanf("%d", &T);
while (T--) {
pa = pb = pc = pd = pe = em;
int n,k,l;
n = read();
k = read();
l = read();
for (int i = 0; i < n; i++) sa[i] = read();
for (int i = 0; i < n; i++) sb[i] = read();
for (int i = 0; i < n; i++) {
pa.push(SJd(sa[i], i));
pb.push(SJd(sb[i], i));
pe.push(SJd(sa[i] + sb[i], i));
ba[i] = bb[i] = false;
}
int sy = k - l;
ll ans = 0;
for (int i = 0; i < k; i++) {
SJd ra,rb,rc,rd,re;
while (!pa.empty()) {
ra = pa.top();
if (!ba[ra.i]) break;
pa.pop();
}
while (!pb.empty()) {
rb = pb.top();
if (!bb[rb.i]) break;
pb.pop();
}
if (sy > 0) {
if (bb[ra.i]) sy += 1;
if (ba[rb.i]) sy += 1;
if (ra.i == rb.i) sy += 1;
ba[ra.i] = bb[rb.i] = true;
pc.push(SJd(sa[rb.i], rb.i));
pd.push(SJd(sb[ra.i], ra.i));
sy -= 1;
ans += ra.z + rb.z;
continue;
}
while (!pc.empty()) {
rc = pc.top();
if (!ba[rc.i]) break;
pc.pop();
}
while (!pd.empty()) {
rd = pd.top();
if (!bb[rd.i]) break;
pd.pop();
}
while (!pe.empty()) {
re = pe.top();
if (!ba[re.i] && !bb[re.i]) break;
pe.pop();
}
int ma = -1,
lx = -1;
if (!pc.empty() && !pb.empty() && rc.z + rb.z > ma) ma = rc.z + rb.z,lx = 1;
if (!pd.empty() && !pa.empty() && rd.z + ra.z > ma) ma = rd.z + ra.z,lx = 2;
if (!pe.empty() && re.z > ma) ma = re.z,lx = 3;
ans += ma;
if (lx == 1) {
if (ba[rb.i]) sy += 1;
ba[rc.i] = bb[rb.i] = true;
pc.pop();
pb.pop();
pc.push(SJd(sa[rb.i], rb.i));
} else if (lx == 2) {
if (bb[ra.i]) sy += 1;
ba[ra.i] = bb[rd.i] = true;
pa.pop();
pd.pop();
pd.push(SJd(sb[ra.i], ra.i));
} else if (lx == 3) {
ba[re.i] = bb[re.i] = true;
pe.pop();
}
}
printf("%lld\n", ans);
}
return 0;
}
[NOI2019]序列(模拟费用流)的更多相关文章
- luogu P5470 [NOI2019]序列 dp 贪心 费用流 模拟费用流
LINK:序列 考虑前20分 容易想到爆搜. 考虑dp 容易设\(f_{i,j,k,l}\)表示前i个位置 选了j对 且此时A选择了k个 B选择了l个的最大值.期望得分28. code //#incl ...
- 模拟费用流 & 可撤销贪心
1. CF730I Olympiad in Programming and Sports 大意: $n$个人, 第$i$个人编程能力$a_i$, 运动能力$b_i$, 要选出$p$个组成编程队, $s ...
- Codeforces 280D k-Maximum Subsequence Sum [模拟费用流,线段树]
洛谷 Codeforces bzoj1,bzoj2 这可真是一道n倍经验题呢-- 思路 我首先想到了DP,然后矩阵,然后线段树,然后T飞-- 搜了题解之后发现是模拟费用流. 直接维护选k个子段时的最优 ...
- 【BZOJ3502/2288】PA2012 Tanie linie/【POJ Challenge】生日礼物 堆+链表(模拟费用流)
[BZOJ3502]PA2012 Tanie linie Description n个数字,求不相交的总和最大的最多k个连续子序列. 1<= k<= N<= 1000000. Sam ...
- 贪心(模拟费用流):NOIP2011 观光公交
[问题描述] 风景迷人的小城Y 市,拥有n 个美丽的景点.由于慕名而来的游客越来越多,Y 市特意安排了一辆观光公交车,为游客提供更便捷的交通服务.观光公交车在第0 分钟出现在1号景点,随后依次前往2. ...
- BZOJ4977[Lydsy1708月赛]跳伞求生——贪心+堆+模拟费用流
题目链接: 跳伞求生 可以将题目转化成数轴上有$n$个人和$m$个房子,坐标分别为$a_{i}$和$b_{i}$,每个人可以进一个他左边的房子,每个房子只能进一个人.每个房子有一个收益$c_{i}$, ...
- 【bzoj1150】[CTSC2007]数据备份Backup 模拟费用流+链表+堆
题目描述 你在一家 IT 公司为大型写字楼或办公楼(offices)的计算机数据做备份.然而数据备份的工作是枯燥乏味的,因此你想设计一个系统让不同的办公楼彼此之间互相备份,而你则坐在家中尽享计算机游戏 ...
- [UOJ455][UER #8]雪灾与外卖——堆+模拟费用流
题目链接: [UOJ455]雪灾与外卖 题目描述:有$n$个送餐员(坐标为$x_{i}$)及$m$个餐厅(坐标为$y_{i}$,权值为$w_{i}$),每个送餐员需要前往一个餐厅,每个餐厅只能容纳$c ...
- BZOJ4849[Neerc2016]Mole Tunnels——模拟费用流+树形DP
题目描述 鼹鼠们在底下开凿了n个洞,由n-1条隧道连接,对于任意的i>1,第i个洞都会和第i/2(取下整)个洞间有一条隧 道,第i个洞内还有ci个食物能供最多ci只鼹鼠吃.一共有m只鼹鼠,第i只 ...
随机推荐
- 长乐培训Day3
T1 奶牛晒衣服 题目 [题目描述] 在熊大妈英明的带领下,时针和他的同伴生下了许多牛宝宝.熊大妈决定给每个宝宝都穿上可爱的婴儿装.于是,为牛宝宝洗晒衣服就成了很不爽的事情. 圣人王担负起了这个重任. ...
- CSS实现自适应分隔线的N种方法
分割线是网页中比较常见的一类设计了,比如说知乎的更多回答 这里的自适应是指两边的横线会随着文字的个数和父级的宽度自适应 偷偷的看了一下知乎的实现,很显然是用一块白色背景覆盖的,加一点背景就露馅了 心想 ...
- 使用Android Studio遇到的问题
学校这课程安排没明白...又要写安卓了. 这里把使用Android Studio3.1时遇到的问题记录下. Android Studio无法启动模拟器 解决: 控制面板->程序->关闭Hy ...
- LeetCode每日一练(1-3)
题目导航 1. 两数之和 2. 两数相加 3. 无重复字符的最长子串 1. 两数之和 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的 ...
- ASP.NET Core 2.1 中的 HttpClientFactory (Part 1) HttpClientFactory介绍
原文:https://www.stevejgordon.co.uk/introduction-to-httpclientfactory-aspnetcore 发表于:2018年1月 ASP.NET ...
- Eva 剧情解析
Eva 剧情解析 来源 https://zhuanlan.zhihu.com/p/20864898 [0.写在前面的话] 相信和我年龄差不多的小伙伴们对<新世纪福音战士>( <Neo ...
- 【转载】网站配置Https证书系列(三):IIS网站设置Http链接直接跳转Https安全连接
Http链接请求是以明文的方式传输,在传输的过程中很容易被篡改数据,一个典型的例子就是运营商的网络劫持注入广告信息等,而Https请求则是安全加密的请求,报文数据以密文的形式进行传输.当IIS网站配置 ...
- python渗透库大集合
l Scapy:一款强大的交互式数据报分析工具,可用作发送.嗅探.解析和伪造网络数据包. l pypcap.Pcapy和pylibpcap:配合libpcap一起使用的数据包捕获模块 l libdne ...
- 【转载】2018年最值得期待的5大BPM厂商
部署BPM软件可以帮助企业获得竞争优势,通过分析.设计.执行.控制和调节业务流程协助企业领导者提高组织绩效. 业务流程管理(BPM)是指随着公司和组织的发展匹配业务目标和流程的行为.部署BPM软件可以 ...
- iOS毛玻璃效果的实现方法
ios开发中常常用到的毛玻璃效果实现方法 iOS8以后使用系统里的UIBlurEffect可以实现,UIBlurEffect继承自UIVisualEffect UIBlurEffectStyle有三个 ...