P5470 [NOI2019]序列
链接:https://www.luogu.com.cn/problem/P5470
题目描述:给定两个序列,在两个序列中分别取出两个大小为下标集使得交的个数,最大化取出下标的对应元素权值和。
题解:首先可以建出费用流模型:
令序列元素为,序列元素为,
然后连,流量为,费用为
连,流量为,费用为
连,流量为,费用为
由于有的限制,那么随便连就有的限制:
那么可以连,流量为,费用为
那么可以连,流量为,费用为
那么可以连,流量为,费用为
当然对于源点要限制只有大小为的流,那么连,流量为,费用为,将置为源点。
现在考虑有以下几种流:
.,即选两个下标相当的元素。
.,即选两个下标不相当的元素,此时花费流量。
.,此时时被翻转的,从前就被流过,那么就是选了,即选了被使用过的一个与一个,不花费流量。
,不难发现有一种与对称的流,选了被使用过的一个与一个,不花费流量。
.,此时,,均被翻转过。那么,即选了被使用过的一个与一个被使用的,反加流量。而它的对称流还是。
所以我们可以拿个堆模拟上述过程,令表示没用过的集合,表示没用过的集合,表示用过的集合,表示用过的集合,表示都没用过组成的集合。
则即
即
即
即
即
然后模拟费用流即可,注意包含了,所以可能会有被误判为的情况,将置在前即可。
#include<iostream>
#include<queue>
#include<cstdio>
using namespace std;
struct reads
{
long long num,data;
bool operator < (const reads &a)const
{
return data<a.data;
}
};
priority_queue<reads>qa;
priority_queue<reads>qb;
priority_queue<reads>ta;
priority_queue<reads>tb;
priority_queue<reads>p;
long long T,n,k,L,s,maxn,maxer,ans,A[1000001],B[1000001];
bool t,usedA[1000001],usedB[1000001];
int read()
{
char c=0;
int sum=0;
while (c<'0'||c>'9')
c=getchar();
while ('0'<=c&&c<='9')
{
sum=sum*10+c-'0';
c=getchar();
}
return sum;
}
reads tmp;
reads make_reads(int x,int y)
{
tmp.num=x;
tmp.data=y;
return tmp;
}
int main()
{
T=read();
while (T--)
{
n=read(),k=read(),L=read();
while (!qa.empty())
qa.pop();
while (!qb.empty())
qb.pop();
while (!p.empty())
p.pop();
while (!ta.empty())
ta.pop();
while (!tb.empty())
tb.pop();
for (int i=1;i<=n;++i)
{
usedA[i]=0;
A[i]=read();
qa.push(make_reads(i,A[i]));
}
for (int i=1;i<=n;++i)
{
usedB[i]=0;
B[i]=read();
qb.push(make_reads(i,B[i]));
}
for (int i=1;i<=n;++i)
p.push(make_reads(i,A[i]+B[i]));
s=k-L;
ans=0;
while (k--)
{
maxn=0;
while (!qa.empty()&&usedB[qa.top().num])
qa.pop();
while (!qb.empty()&&usedA[qb.top().num])
qb.pop();
while (!p.empty()&&(usedA[p.top().num]||usedB[p.top().num]))
p.pop();
if (!p.empty()&&p.top().data>maxn)
{
maxn=p.top().data;
maxer=5;
}
if (s)
{
if (!qa.empty()&&!qb.empty()&&qa.top().data+qb.top().data>maxn)
{
maxn=qa.top().data+qb.top().data;
maxer=1;
}
}
if (!qa.empty()&&!tb.empty()&&qa.top().data+tb.top().data>maxn)
{
maxn=qa.top().data+tb.top().data;
maxer=2;
}
if (!ta.empty()&&!qb.empty()&&ta.top().data+qb.top().data>maxn)
{
maxn=ta.top().data+qb.top().data;
maxer=3;
}
if (!ta.empty()&&!tb.empty()&&ta.top().data+tb.top().data>maxn)
{
maxn=ta.top().data+tb.top().data;
maxer=4;
}
ans+=maxn;
if (maxer==1)
{
s--;
tb.push(make_reads(qa.top().num,B[qa.top().num]));
ta.push(make_reads(qb.top().num,A[qb.top().num]));
usedA[qa.top().num]=1;
usedB[qb.top().num]=1;
qa.pop();
qb.pop();
}
if (maxer==2)
{
usedA[qa.top().num]=1;
usedB[tb.top().num]=1;
tb.pop();
tb.push(make_reads(qa.top().num,B[qa.top().num]));
qa.pop();
}
if (maxer==3)
{
usedA[ta.top().num]=1;
usedB[qb.top().num]=1;
ta.pop();
ta.push(make_reads(qb.top().num,A[qb.top().num]));
qb.pop();
}
if (maxer==4)
{
s++;
usedA[ta.top().num]=1;
usedB[tb.top().num]=1;
ta.pop();
tb.pop();
}
if (maxer==5)
{
usedA[p.top().num]=1;
usedB[p.top().num]=1;
}
}
printf("%lld\n",ans);
}
return 0;
}
作者:zhouhuanyi
出处:https://www.cnblogs.com/zhouhuanyi/p/16983731.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?