Loading

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;
}
posted @ 2022-12-14 21:55  zhouhuanyi  阅读(41)  评论(0)    收藏  举报