loj 3158 [NOI2019]序列
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\n",an);
}
return 0;
}