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;
    } 
    

      

  • 相关阅读:
    toj 2819 Travel
    toj 2807 Number Sort
    zoj 2818 Prairie dogs IV
    zoj 1276 Optimal Array Multiplication Sequence
    toj 2802 Tom's Game
    toj 2798 Farey Sequence
    toj 2815 Searching Problem
    toj 2806 Replace Words
    toj 2794 Bus
    css截取字符
  • 原文地址:https://www.cnblogs.com/Memory-of-winter/p/9486197.html
Copyright © 2011-2022 走看看