loj 3158 [NOI2019]序列

loj 3158 [NOI2019]序列

https://loj.ac/problem/3158

UP5sE9.png

UP5641.png

Tutorial

https://www.luogu.com.cn/blog/s-r-f/solution-p5470

考虑建立费用流模型

建立\(n\)个点表示\(a_i\),\(n\)个点表示\(b_i\),两个中转点\(u,v\)

源点向每个表示\(a_i\)的点连\((1,a_i)\),每个表示\(b_i\)的点向汇点连\((1,b_i)\),表示\(a_i\)的点和表示\(b_i\)的对应的点之间连\((\infty,0)\)

\(u\)\(v\)\((K-L,0)\)表示可以不相同的下标对数.每个表示\(a_i\)的点向\(u\)\((\infty,0)\),\(v\)向每个表示\(b_i\)的连\((\infty,0)\).注意优先流对应的点之间的边.

我们要求的就是流量为\(K\)时的最大费用.

用模拟费用流解决,注意维护\(u,v\)之间的边剩余的流量,并尽量使其最大

  1. \(u,v\)之间未满流,则分别选择\(a,b\)中最大的点

  2. 否则,有\(3\)种选择.

  1. 选择一对没有选择过的\(a,b\)
  2. 选择一个\(a\)已经被选过的\(b\),和一个未选择的\(a\)
  3. 选择一个\(b\)已经被选过的\(a\),和一个未选择的\(b\)

注意2,3可能会产生新的\(u,v\)间流量

Code

#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define fi first
#define se second
using namespace std;
inline char gc() {
	static char buf[100000],*l=buf,*r=buf;
	return l==r&&(r=(l=buf)+fread(buf,1,100000,stdin),l==r)?EOF:*l++;
}
template<class T> void rd(T &x) {
	x=0; int f=1,ch=gc();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=gc();}
	while(ch>='0'&&ch<='9'){x=x*10-'0'+ch;ch=gc();}
	x*=f;
}
typedef long long ll;
const int inf=1e9;
const int maxn=2e5+50;
int T,n,K,L,a[maxn],b[maxn];
int s[maxn];
int main() {
	freopen("sequence.in","r",stdin);
	freopen("sequence.out","w",stdout);
	rd(T);
	for(int kase=1;kase<=T;++kase) {
		rd(n),rd(K),rd(L);
		for(int i=1;i<=n;++i) rd(a[i]);
		for(int i=1;i<=n;++i) rd(b[i]);
		priority_queue< pair<int,int> > qa,qA,qb,qB,qab;
		{
			pair<int,int> t(-inf,0);
			qa.push(t),qA.push(t),qb.push(t),qB.push(t),qab.push(t);
		}
		memset(s,0,sizeof(s));
		for(int i=1;i<=n;++i) {
			qa.push(make_pair(a[i],i));
			qb.push(make_pair(b[i],i));
			qab.push(make_pair(a[i]+b[i],i));
		}
		ll an=0;
		for(int i=1,flow=K-L;i<=K;++i) {
			while(s[qa.top().se]&1) qa.pop();
			while(s[qA.top().se]&1) qA.pop();
			while(s[qb.top().se]&2) qb.pop();
			while(s[qB.top().se]&2) qB.pop();
			while(s[qab.top().se]) qab.pop();
			if(flow) {
				int p=qa.top().se,q=qb.top().se;
				an+=a[p]+b[q]; 
				s[p]|=1,qB.push(make_pair(b[p],p));
				s[q]|=2,qA.push(make_pair(a[q],q));
				if(p!=q) {
					--flow;
					if(s[q]==3) ++flow;
					if(s[p]==3) ++flow;
				}
				continue;
			}
			int v0=qA.top().fi+qb.top().fi; bool c0=s[qb.top().se];
			int v1=qa.top().fi+qB.top().fi; bool c1=s[qa.top().se];
			int v2=qab.top().fi;
			if(make_pair(v0,c0)>=make_pair(v1,c1)&&v0>=v2) {
				int p=qA.top().se,q=qb.top().se;
				an+=v0,flow+=c0;
				s[p]|=1;
				s[q]|=2,qA.push(make_pair(a[q],q));
			}
			else if(v1>=v2) {
				int p=qa.top().se,q=qB.top().se;
				an+=v1,flow+=c1;
				s[p]|=1,qB.push(make_pair(b[p],p));
				s[q]|=2;
			}
			else {
				int p=qab.top().se;
				an+=v2;
				s[p]=3;
			}
		}
		printf("%lld\n",an);
	}
	return 0;
}
posted @ 2020-07-06 17:53  LJZ_C  阅读(165)  评论(0编辑  收藏  举报