zoukankan      html  css  js  c++  java
  • 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
    ",an);
    	}
    	return 0;
    }
    
  • 相关阅读:
    atoi (String to Integer) leetcode
    按层逆遍历一棵树,使用满二叉树存储
    unix网络编程-配置unp.h头文件
    ListView系列(七)——Adapter内的onItemClick监听器四个arg参数
    Windows系统下安装VirtualBox,系统找不到指定路径的做法
    Android Fragment完全解析,关于碎片你所需知道的一切
    【Android开源框架列表】
    fragment报错
    2013 年开源中国 10 大热门 Java 开源项目
    【移动开发】Android中三种超实用的滑屏方式汇总(ViewPager、ViewFlipper、ViewFlow)
  • 原文地址:https://www.cnblogs.com/ljzalc1022/p/13256078.html
Copyright © 2011-2022 走看看