loj 3158 [NOI2019]序列
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)之间的边剩余的流量,并尽量使其最大
-
若(u,v)之间未满流,则分别选择(a,b)中最大的点
-
否则,有(3)种选择.
- 选择一对没有选择过的(a,b)
- 选择一个(a)已经被选过的(b),和一个未选择的(a)
- 选择一个(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
",an);
}
return 0;
}