zoukankan      html  css  js  c++  java
  • BZOJ3532 [Sdoi2014]Lis 【网络流退流】

    题目

    给定序列A,序列中的每一项Ai有删除代价Bi和附加属性Ci。请删除若
    干项,使得4的最长上升子序列长度减少至少1,且付出的代价之和最小,并输出方案。
    如果有多种方案,请输出将删去项的附加属性排序之后,字典序最小的一种。

    输入格式

    输入包含多组数据。
    输入的第一行包含整数T,表示数据组数。接下来4*T行描述每组数据。
    每组数据的第一行包含一个整数N,表示A的项数,接下来三行,每行N个整数A1..An,B1.,Bn,C1..Cn,满足1 < =Ai,Bi,Ci < =10^9,且Ci两两不同。

    输出格式

    对每组数据,输出两行。第一行包含两个整数S,M,依次表示删去项的代价和与数量;接下来一行M个整数,表示删去项在4中的的位置,按升序输出。
    

    输入样例

    1
    
    6
    
    3 4 4 2 2 3
    
    2 1 1 1 1 2
    
    6 5 4 3 2 1
    

    输出样例

    4 3
    
    2 3 6
    

    解释:删去(A2,43,A6),(A1,A6),(A2,43,44,A5)等都是合法的方案,但

    {A2,43,A6)对应的C值的字典序最小。

    提示

    1 < =N < =700 T < =5

    题解

    被卡常了,,,
    求LIS还是得二分

    首先,由经典建模,我们可以求出问题的答案
    每个点拆点,代价为权值,然后S向LIS为1的点连边,LIS最大的向T连边

    最难的是求方案

    割的判定:
    对于边(u,v)如果残量网络中不存在任何一条从u到v的增广路,说明(u,v)为割

    我们按C从小到大枚举点,如果为割则加入答案
    然后要删掉(u,v)这条边,防止对其它点判定的影响
    先撤回流量,再置容量为0

    撤回流量:
    跑一遍T到v的最大流,再跑一遍u到S的最大流

    然后就可以A了 才怪,小心卡常

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<queue>
    #include<cstring>
    #include<algorithm>
    #define LL long long int
    #define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
    #define REP(i,n) for (int i = 1; i <= (n); i++)
    #define BUG(s,n) for (int i = 1; i <= (n); i++) cout<<s[i]<<' '; puts("");
    #define cls(x) memset(x,0,sizeof(x))
    using namespace std;
    const int maxn = 1405,maxm = 2000005;
    const LL INF = 10000000000000000ll;
    inline int read(){
    	int out = 0,flag = 1; char c = getchar();
    	while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
    	while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
    	return out * flag;
    }
    int h[maxn],ne = 2;
    struct EDGE{int to,nxt; LL f;}ed[maxm];
    inline void build(int u,int v,LL f){
    	ed[ne] = (EDGE){v,h[u],f}; h[u] = ne++;
    	ed[ne] = (EDGE){u,h[v],0}; h[v] = ne++;
    }
    int n,A[maxn],B[maxn],C[maxn],id[maxn],m;
    LL vis[maxn],d[maxn];
    int S,T,oute[maxn],cur[maxn];
    inline bool cmp(const int& a,const int& b){
    	return C[a] < C[b];
    }
    int f[maxn],bac[maxn];
    int find(int x){
    	int l = 0,r = n,mid;
    	while (l < r){
    		mid = l + r + 1 >> 1;
    		if (bac[mid] < x) l = mid;
    		else r = mid - 1;
    	}
    	return l;
    }
    void init(){
    	ne = 2;
    	n = read(); m = (n << 1 | 1);
    	for (int i = 0; i <= m; i++) h[i] = 0,bac[i] = INF;
    	REP(i,n) A[i] = read();
    	REP(i,n) B[i] = read();
    	REP(i,n) C[i] = read(),id[i] = i;
    	sort(id + 1,id + 1 + n,cmp);
    	S = 0; T = 2 * n + 1;
    	for (int i = 1; i <= n; i++){
    		f[i] = max(1,find(A[i]) + 1);
    		bac[f[i]] = min(bac[f[i]],A[i]);
    	}
    	int ans = 0;
    	for (int i = 1; i <= n; i++) ans = max(ans,f[i]);
    	for (int i = 1; i <= n; i++){
    		if (f[i] == 1) build(S,i,INF);
    		else if (f[i] == ans) build(i + n,T,INF);
    		oute[i] = ne;
    		build(i,i + n,B[i]);
    		for (int j = i + 1; j <= n; j++)
    			if (f[j] == f[i] + 1 && A[i] < A[j])
    				build(i + n,j,INF);
    	}
    }
    int q[2 * maxn],head,tail;
    bool bfs(){
    	for (int i = 0; i <= m; i++) d[i] = -1;
    	q[head = tail = 1] = S;
    	d[S] = 1;
    	int u;
    	while (head <= tail){
    		u = q[head++];
    		Redge(u) if (ed[k].f && d[to = ed[k].to] == -1){
    			d[to] = d[u] + 1;
    			q[++tail] = to;
    			if (to == T) return true;
    		}
    	}
    	return false;
    }
    LL dfs(int u,LL minf){
    	if (u == T || !minf) return minf;
    	LL flow = 0,f; int to;
    	if (cur[u] == -1) cur[u] = h[u];
    	for (int& k = cur[u]; k; k = ed[k].nxt)
    		if (d[to = ed[k].to] == d[u] + 1 && (f = dfs(to,min(minf,ed[k].f)))){
    			ed[k].f -= f; ed[k ^ 1].f += f;
    			minf -= f; flow += f;
    			if (!minf) break;
    		}
    	return flow;
    }
    LL maxflow(){
    	LL flow = 0;
    	while (bfs()){
    		for (int i = 0; i <= m; i++) cur[i] = -1;
    		flow += dfs(S,INF);
    	}
    	return flow;
    }
    int ans[maxn],ansi;
    void solve(){
    	printf("%lld ",maxflow());
    	ansi = 0;
    	for (int i = 1; i <= n; i++){
    		int u = id[i];
    		if (!ed[oute[u]].f){
    			S = u; T = u + n;
    			if (bfs()) continue;
    			ans[++ansi] = u;
    			S = 2 * n + 1; T = u + n;
    			maxflow();
    			S = u; T = 0;
    			maxflow();
    			ed[oute[u]].f = ed[oute[u] ^ 1].f = 0;
    		}
    	}
    	printf("%d
    ",ansi);
    	if (ansi){
    		sort(ans + 1,ans + 1 + ansi);
    		printf("%d",ans[1]);
    		for (int i = 2; i <= ansi; i++)
    			printf(" %d",ans[i]);
    		puts("");
    	}
    }
    int main(){
    	int t = read();
    	while (t--){
    		init();
    		solve();
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    sp_executesql介绍和使用
    jQuery中的 return false, e.preventDefault(), e.stopPropagation()的区别
    clearfix:after 清除css浮动
    paip.mysql 性能跟iops的以及硬盘缓存的关系
    paip.mysql 性能测试 报告 home right
    paip.mysql 性能测试by mysqlslap
    paip.java 架构师之路以及java高级技术
    paip. 提升性能---hibernate的缓存使用 总结
    paip. 解决php 以及 python 连接access无效的参数量。参数不足,期待是 1”的错误
    paip.解决access出现 -2147467259 无效的参数量
  • 原文地址:https://www.cnblogs.com/Mychael/p/8681610.html
Copyright © 2011-2022 走看看