P5470 [NOI2019]序列
链接:https://www.luogu.com.cn/problem/P5470
题目描述:给定两个序列\(a,b\),在两个序列中分别取出两个大小为\(K\)下标集\(A,B\)使得\(A,B\)交的个数\(>=L\),最大化取出下标的对应元素权值和。
题解:首先可以建出费用流模型:
令序列\(A\)元素为\(i\),序列\(B\)元素为\(i'\),
然后连\((s,i)\),流量为\(1\),费用为\(a_{i}\)
连\((i',t)\),流量为\(1\),费用为\(b_{i}\)
连\((i,i')\),流量为\(1\),费用为\(0\)
由于有\(L\)的限制,那么随便连就有\(K-L\)的限制:
那么可以连\((i,U)\),流量为\(1\),费用为\(0\)
那么可以连\((U,V)\),流量为\(K-L\),费用为\(0\)
那么可以连\((V,i')\),流量为\(1\),费用为\(0\)
当然对于源点要限制只有大小为\(K\)的流,那么连\((s',s)\),流量为\(K\),费用为\(0\),将\(s'\)置为源点。
现在考虑有以下几种流:
\(1\).\(s->i->i'->t\),即选两个下标相当的元素。
\(2\).\(s->i->U->V->j'->t\),即选两个下标不相当的元素,此时\((U,V)\)花费\(1\)流量。
\(3\).\(s->i->i'->V->j'->t\),此时\(i'->V\)时被翻转的,从前\(i'\)就被流过,那么就是选了\(i,j'\),即选了\(i'\)被使用过的一个\(i\)与一个\(j'\),不花费\((U,V)\)流量。
\(4\),不难发现有一种与\(3\)对称的流,选了\(i\)被使用过的一个\(i'\)与一个\(j\),不花费\((U,V)\)流量。
\(5\).\(s->i->i'->V->U->j->j'->t\),此时\((i',V)\),\((V,U)\),\((U,j)\)均被翻转过。那么,即选了\(i'\)被使用过的一个\(i\)与一个\(j\)被使用的\(j'\),反加\((U,V)\)流量。而它的对称流还是\(5\)。
所以我们可以拿\(5\)个堆模拟上述过程,令\(qa\)表示没用过\(i'\)的\(i\)集合,\(qb\)表示没用过\(j'\)的\(j\)集合,\(ta\)表示用过\(i'\)的\(i\)集合,\(tb\)表示用过\(j'\)的\(j\)集合,\(p\)表示\(i,i'\)都没用过组成的集合。
则\(1\)即\(p\)
\(2\)即\(qa+qb\)
\(3\)即\(ta+qb\)
\(4\)即\(qa+tb\)
\(5\)即\(ta+tb\)
然后模拟费用流即可,注意\(p\)包含了\(qa,qb\),所以可能会有\(1\)被误判为\(2\)的情况,将\(1\)置在\(2\)前即可。
#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

浙公网安备 33010602011771号