【题解】Luogu P5470 [NOI2019]序列
原题传送门
同步赛上我一开始想了个看似正确却漏洞百出的贪心:按\(a_i+b_i\)的和从大向小贪心
随便想想发现是假的,然后就写了个28pts的暴力dp
杜神后半程说这题就是个贪心,但我没时间写了 (实际是没想明白)
我们来说这道题的正解:
我们先珂以满足和最大,再满足并集大小大于等于\(l\)。所以我们先将\(a\)序列和\(b\)序列排序,取出两个序列的前\(k\)大
如果并集大小大于等于\(l\)就直接统计答案
否则我们要凑满\(l\)个都包含的,在凑的过程中动态更新答案
我们在两个序列中都选中前\(k-l\)个不含有并集的数,并加入答案中,易知这些数一定含在答案中(这个珂以在草稿纸上推一推)。接下来考虑如何凑并集元素,一次凑一组:
1.两个都没被选中的情况下的最大值,并将它们选中
2.一个被选中的情况下的最大值。假设\(a[rk[i]]\)选中了,但\(b[rk[i]]\)没选中,我们就要找到一个最小的j使得\(a[rk[j]]\)没被选中,我们就珂以选中\(b[rk[i]\)和\(a[rk[j]]\),使得a中不成对的还是\(k-l\)个。a,b反之亦然
我们求出1、2两种情况贡献最大值并更新选中状态(都用堆维护,具体细节见代码),重复\(l\)次即可求出答案
注意:两次2也许就会将两个都没选中的变成都选中,所以要及时舍掉不合法的
#include <bits/stdc++.h>
#define N 200005
#define ll long long
#define getchar nc
using namespace std;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int read()
{
register int x=0,f=1;register char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return x*f;
}
inline void write(register ll x)
{
if(!x)putchar('0');if(x<0)x=-x,putchar('-');
static int sta[20];register int tot=0;
while(x)sta[tot++]=x%10,x/=10;
while(tot)putchar(sta[--tot]+48);
}
int T,n,k,l,a[N],b[N],ar[N],br[N],va[N],vb[N],vis[N];
ll ans;
inline bool cmpa(register int x,register int y)
{
return a[x]>a[y];
}
inline bool cmpb(register int x,register int y)
{
return b[x]>b[y];
}
struct node{
int pos,val;
inline bool operator < (const node &it) const {
return val<it.val;
}
};
inline bool chkmax(register int &a,register int b)
{
return a<b?a=b,1:0;
}
int main()
{
T=read();
while(T--)
{
n=read(),k=read(),l=read();
for(register int i=1;i<=n;++i)
a[i]=read(),ar[i]=i,va[i]=vb[i]=vis[i]=0;
for(register int i=1;i<=n;++i)
b[i]=read(),br[i]=i;
sort(ar+1,ar+1+n,cmpa);
sort(br+1,br+1+n,cmpb);
for(register int i=1;i<=k;++i)
va[ar[i]]=1,vb[br[i]]=1;
ans=0;
priority_queue<int> pa,pb;
priority_queue<node> qa,qb;
for(register int i=1;i<=n;++i)
if(va[i]&&vb[i])
qb.push((node){i,a[i]+b[i]}),vis[i]=1;
if(qb.size()>=l)
{
for(register int i=1;i<=n;++i)
{
if(va[i])
ans+=a[i];
if(vb[i])
ans+=b[i];
}
}
else
{
for(register int i=1,tot=0;i<=k;++i)
if(!vb[ar[i]])
{
if(tot<k-l)
ans+=a[ar[i]],vis[ar[i]]=1,pa.push(b[ar[i]]);
else
qa.push((node){ar[i],a[ar[i]]+b[ar[i]]});
++tot;
}
for(register int i=1,tot=0;i<=n;++i)
if(!va[br[i]])
{
if(tot<k-l)
ans+=b[br[i]],vis[br[i]]=1,pb.push(a[br[i]]);
else
qb.push((node){br[i],a[br[i]]+b[br[i]]});
++tot;
}
int af=1,bf=1;
while(l--)
{
while(af<=k&&vis[ar[af]])
++af;
while(bf<=k&&vis[br[bf]])
++bf;
while(!qa.empty()&&vis[qa.top().pos]&&!(va[qa.top().pos]&&vb[qa.top().pos]))
qa.pop();
while(!qb.empty()&&vis[qb.top().pos]&&!(va[qb.top().pos]&&vb[qb.top().pos]))
qb.pop();
int maxx=0,typ=-1;
if(!qa.empty())
maxx=qa.top().val,typ=0;
if(!qb.empty()&&chkmax(maxx,qb.top().val))
typ=1;
if(!pa.empty()&&af<=k&&chkmax(maxx,pa.top()+a[ar[af]]))
typ=2;
if(!pb.empty()&&bf<=k&&chkmax(maxx,pb.top()+b[br[bf]]))
typ=3;
ans+=maxx;
if(typ==0)
vis[qa.top().pos]=1,qa.pop();
else if(typ==1)
vis[qb.top().pos]=1,qb.pop();
else if(typ==2)
vis[ar[af]]=1,pa.pop(),pa.push(b[ar[af]]);
else
vis[br[bf]]=1,pb.pop(),pb.push(a[br[bf]]);
}
}
write(ans),puts("");
}
return 0;
}
【题解】Luogu P5470 [NOI2019]序列的更多相关文章
- luogu P5470 [NOI2019]序列 dp 贪心 费用流 模拟费用流
LINK:序列 考虑前20分 容易想到爆搜. 考虑dp 容易设\(f_{i,j,k,l}\)表示前i个位置 选了j对 且此时A选择了k个 B选择了l个的最大值.期望得分28. code //#incl ...
- Luogu P5470 [NOI2019]序列
题目 可以直接贪心,但是用模拟费用流推的话会更轻松. 首先有一个显然的建图方式: \(S\)到\(0\)流量为\(k\),费用为\(0\). \(0\)到\(a_i\)流量为\(1\),费用为\(-a ...
- 洛谷 P5470 - [NOI2019] 序列(反悔贪心)
洛谷题面传送门 好几天没写题解了,写篇题解意思一下(大雾 考虑反悔贪心,首先我们考虑取出 \(a,b\) 序列中最大的 \(k\) 个数,但这样并不一定满足交集 \(\ge L\) 的限制,因此我们需 ...
- [luogu P3648] [APIO2014]序列分割
[luogu P3648] [APIO2014]序列分割 题目描述 小H最近迷上了一个分隔序列的游戏.在这个游戏里,小H需要将一个长度为n的非负整数序列分割成k+1个非空的子序列.为了得到k+1个子序 ...
- [题解] Luogu P5446 [THUPC2018]绿绿和串串
[题解] Luogu P5446 [THUPC2018]绿绿和串串 ·题目大意 定义一个翻转操作\(f(S_n)\),表示对于一个字符串\(S_n\), 有\(f(S)= \{S_1,S_2,..., ...
- 【题解】Luogu P2572 [SCOI2010]序列操作
原题传送门:P2572 [SCOI2010]序列操作 这题好弱智啊 裸的珂朵莉树 前置芝士:珂朵莉树 窝博客里对珂朵莉树的介绍 没什么好说的自己看看吧 操作1:把区间内所有数推平成0,珂朵莉树基本操作 ...
- 【题解】Luogu P5294 [HNOI2019]序列
原题传送门 题意:给你一个长度为\(n\)的序列\(A\),每次询问修改一个元素(只对当前询问有效),然后让你找到一个不下降序列\(B\),使得这两个序列相应位置之差的平方和最小,并输出这个最小平方和 ...
- 【题解】Luogu P5471 [NOI2019]弹跳
原题传送门 先考虑部分分做法: subtask1: 暴力\(O(nm)\)枚举,跑最短路 subtask2: 吧一行的点压到vector中并排序,二分查找每一个弹跳装置珂以到达的城市,跑最短路 sub ...
- 【题解】Luogu P5468 [NOI2019]回家路线
原题传送门 前置芝士:斜率优化 不会的可以去杜神博客学 这道题我考场上只会拆点跑最短路的70pts做法 后来回家后发现错误的爆搜都能拿满分(刀片) 还有很多人\(O(mt)\)过的,还是要坚持写正解好 ...
随机推荐
- Linux的权限管理操作-Linux从入门到精通第八天(非原创)
文章大纲 一.网络相关概述二.网络相关命令三.项目上线流程(必须掌握)四.学习资料下载五.参考文章 一.网络相关概述 1. 网络发展 1.1 信息传递远古时期,人们就通过简单的语言.壁画等方式交 ...
- 206--Reverse A Singly Linked List
package LinedList; public class ReverseASinglyLinkedList { //解法一:迭代. public ListNode reverseList(Lis ...
- OGG 源端与目标端 约束不一致
需求: 请在生产库执行下面的脚本 --删除主键并新增复合主键 alter table XXXXX drop constraint PK_USERCHNL cascade; ...
- Linux操作系统的压缩、解压缩工具介绍
Linux操作系统的压缩.解压缩工具介绍 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.compress/uncompress命令常用参数 Linux compress命令: ...
- POJ3070 斐波那契数列递推 矩阵快速幂模板题
题目分析: 对于给出的n,求出斐波那契数列第n项的最后4为数,当n很大的时候,普通的递推会超时,这里介绍用矩阵快速幂解决当递推次数很大时的结果,这里矩阵已经给出,直接计算即可 #include< ...
- Java期末复习——主观题
JDK 和 JRE 有什么区别? JDK:Java Development Kit 的简称,java 开发工具包,提供了 java 的开发环境和运行环境. JRE:Java Runtime Envir ...
- 第06节-开源蓝牙协议BTStack框架分析
本篇博客根据韦东山的视频,整理所得. 本篇博客讲解BTStack的框架,首先来看一下硬件的结构: 蓝牙模块接在电脑上,或是接在开发板上.不论接在哪,我们都需要编写程序来控制这个蓝牙模块. . 我们需要 ...
- NOIP 2013 火柴排队
洛谷 P1966 火柴排队 洛谷传送门 JDOJ 2227: [NOIP2013]火柴排队 D1 T2 JDOJ传送门 Description 涵涵有两盒火柴,每盒装有 n 根火柴,每根火柴都有一个高 ...
- serialize()和new FormData()的区别
serialize()和FormData对象都可将表单数据序列化,后通过ajax异步提交 ,序列化表单就是将form表单中所有name属性序列化成KEY-VALUE的形式,提交到后台,后台以对象相应的 ...
- Shell里的特殊符号
Shell里的特殊符号: (1)单引号: 由单引号括起来的符号都作为普通字符处理,他们都失去了特殊意义. (2)双引号: 除美元符号($).倒引号.反斜线(\)仍保留特殊含义外,其余符号都作为普通字符 ...