zoukankan      html  css  js  c++  java
  • [bzoj3532][Sdoi2014]Lis

    题目大意:给定序列$A$,序列中的每一项$A_i$有删除代价$B_i$和附加属性$C_i$。请删除若干项,使得$A$的最长上升子序列长度至少减少$1$,且代价最小,并输出方案。若有多种方案,$C$的字典序最小的一种。

    题解:如果只要求输出代价,令$f_i$表示到$i$的最长上升子序列长度,把所有$j<i&&a_j<a_i&&f_i=f_j+1$的$i$和$j$之间连一条边,跑一遍最小割就行了。

    但是题目要求字典序最小,可以贪心,按$C$从小到大排序,每次看一条边是否可能是最小割中的边,是的话就删去。

    那么就要求较快出一条边是否可以在最小割中。

    比如求$(u,v)$是否是可以在最小割中,正常的方法是把这条边的容量减$1$,看最小割的大小是不是减少$1$。但这样很慢,这可以转变为在残量网络上看从$u$出发是否能找到一条$u$到$v$的增广路,如果找不到就说明该边可能在最小割中。

    发现,删去一条边后,需要重新计算最大值。

    这时可以使用退流,比如把$(u,v)$退流,就可以在残量网络中跑两遍最大流,分别是$(u,start)$和$(end,v)$,这样就可以把这条边的流量的贡献减去

    卡点:1.$f$数组没清空

    C++ Code:

    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    //#define int long long
    #define maxn 1410
    #define maxm 246000
    #define X(x) ((x << 1) - 1)
    #define Y(x) (x << 1)
    using namespace std;
    const long long inf = 0x3f3f3f3f3f3f3f3f;
    int Tim, n;
    int A[maxn], C[maxn], rnk[maxn], num[maxn];
    int ans[maxn], ansn;
    long long B[maxn];
    int f[maxn], maxf = 0;
    
    int head[maxn], cnt = 2;
    struct Edge {
    	int to, nxt;
    	long long w;
    } e[maxm << 1];
    void add(int a, int b, long long c) {
    	e[cnt] = (Edge) {b, head[a], c}; head[a] = cnt;
    	e[cnt ^ 1] = (Edge) {a, head[b], 0}; head[b] = cnt ^ 1;
    	cnt += 2;
    }
    inline int max(int a, int b) {return a > b ? a : b;}
    inline long long min(long long a, long long b) {return a < b ? a : b;}
    inline bool cmp(int a, int b) {return C[a] < C[b];}
    
    int st, ed, tst, ted;
    int d[maxn];
    int q[maxn], h, t;
    bool bfs() {
    	memset(d, 0, sizeof d);
    	d[q[h = t = 0] = tst] = 1;
    	while (h <= t) {
    		int u = q[h++];
    		if (u == ted) return true;
    		for (int i = head[u]; i; i = e[i].nxt) {
    			int v = e[i].to;
    			if (e[i].w && !d[v]) {
    				d[v] = d[u] + 1;
    				q[++t] = v;
    			}
    		}
    	}
    	return d[ted];
    }
    long long dfs(int x, long long low) {
    //	printf("in:%d %lld
    ", x, low);
    	if (!low || x == ted) return low;
    //	printf("no:%d %lld
    ", x, low);
    	int v;
    	long long res = 0, w;
    	for (int i = head[x]; i; i = e[i].nxt) {
    		v = e[i].to;
    		if (e[i].w && d[v] == d[x] + 1) {
    			w = dfs(v, min(low - res, e[i].w));
    			e[i].w -= w;
    			e[i ^ 1].w += w;
    			res += w;
    			if (low == res) return low;
    		}
    	}
    //	printf("out:%d %lld
    ", x, res);
    	if (!res) d[x] = -1;
    	return res;
    }
    long long dinic(int st, int ed) {
    	tst = st, ted = ed;
    	long long ans = 0;
    	while (bfs()) ans += dfs(tst, inf);
    	return ans;
    }
    signed main() {
    	scanf("%d", &Tim);
    	while (Tim --> 0) {
    		scanf("%d", &n);
    		st = 0, ed = n << 1 | 1;
    		for (int i = 1; i <= n; i++) scanf("%d", &A[i]);
    		for (int i = 1; i <= n; i++) scanf("%lld", &B[i]);
    		for (int i = 1; i <= n; i++) scanf("%d", &C[i]), rnk[i] = i;
    		for (int i = 1; i <= n; i++) {
    			for (int j = 0; j < i; j++) if (A[j] < A[i]) f[i] = max(f[i], f[j] + 1);
    //			printf("%d %d
    ", i, f[i]);
    			maxf = max(maxf, f[i]);
    		}
    //		printf("lalal:%d
    ", maxf);
    		for (int i = 1; i <= n; i++) {
    			num[i] = cnt; add(X(i), Y(i), B[i]);
    			if (f[i] == 1) add(st, X(i), inf);
    			if (f[i] == maxf) add(Y(i), ed, inf);
    			for (int j = i + 1; j <= n; j++) {
    				if (A[i] < A[j] && f[i] + 1 == f[j]) add(Y(i), X(j), inf);
    			}
    		}
    		printf("%lld ", dinic(st, ed));
    		ansn = 0;
    		sort(rnk + 1, rnk + n + 1, cmp);
    		for (int i = 1; i <= n; i++) {
    			int now = rnk[i], E = num[now];
    //			printf("%d %lld
    ", now, e[E].w);
    			if (!e[E].w) {
    				tst = X(now), ted = Y(now);
    				if (!bfs()) {
    					dinic(ed, Y(now));
    					dinic(X(now), st);
    					e[E].w = e[E ^ 1].w = 0;
    					ans[++ansn] = now;
    				}
    			}
    		}
    		sort(ans + 1, ans + ansn + 1);
    		printf("%d
    ", ansn);
    		for (int i = 1; i < ansn; i++) printf("%d ", ans[i]);
    		printf("%d
    ", ans[ansn]);
    		if (Tim) {
    			cnt = 2;
    			memset(f, 0, sizeof f);
    			memset(head, 0, sizeof head);
    			maxf = 0;
    		}
    	}
    	return 0;
    } 
    

      

  • 相关阅读:
    Android的LinearLayout中的权重android:layout_weight
    iPhone尺寸规范
    导出iPhone中安装的APP的iPA文件
    c++ json字符串转换成map管理
    mac 升级EI Capitan后遇到c++转lua时遇到libclang.dylib找不到的错
    sqlite3 数据库使用
    关于flyme5显示不到和卸载不到旧应用解决方法
    cocos2dx 通过jni调用安卓底层方法
    cocos2dx 单张图片加密
    安卓线程使用问题
  • 原文地址:https://www.cnblogs.com/Memory-of-winter/p/9486197.html
Copyright © 2011-2022 走看看