zoukankan      html  css  js  c++  java
  • [BZOJ1283]序列

    [BZOJ1283]序列

    试题描述

    给出一个长度为n的正整数序列Ci,求一个子序列,使得原序列中任意长度为m的子串中被选出的元素不超过K(K,M<=100) 个,并且选出的元素之和最大。

    输入

    第1行三个数N,m,k。 接下来N行,每行一个字符串表示Ci。

    输出

    最大和。

    输入示例

    10 5 3
    4 4 4 6 6 6 6 6 4 4

    输出示例

    30

    数据规模及约定

    20%的数据:n<=10。
    100%的数据:N<=1000,k,m<=100。Ci<=20000。

    题解

    线性规划弱化弱化版。弱化到可以用费用流解决。

    我们设 n 个布尔变量 A[1], A[2], A[3], ... , A[n],其中 A[i] 表示第 i 个数是否选择(0 表示不选,1 表示选)。

    那么得到许多式子(其实是不等式,我们添加辅助变量 B[i],满足所有的 B[i] ≥ 0 就变成等式了):

    A[1] + A[2] + ... + A[m] + B[1] = K…………………………………………………… 1

    A[2] + A[3] + ... + A[m+1] + B[2] = K……………………………………………… 2

    ...

    A[n-m+1] + A[n-m+2] + ... + A[n] + B[n-m+1] = K………………………… n-m+1

    然后用 2 式减去 1 式,3 式减 2 式……n-m+1 式减 n-m 式,得到

    A[m+1] + B[2] = A[1] + B[1]

    A[m+2] + B[3] = A[2] + B[2]

    ...

    A[n] + B[n-m+1] = A[n-m] + B[n-m]

    再添加两个式子(即原来的 1 式和 n-m+1 式):

    A[1] + A[2] + ... + A[m] + B[1] = K

    K = A[n-m+1] + A[n-m+2] + ... + A[n] + B[n-m+1]

    我们会发现所有的 A[i] 和 B[i] 都正好出现在等式的左边和右边各一次。

    这样就可以每个等式看成一个节点,左边有一个变量表示流入,右边有一个变量表示流出,左边有常数表示源点向它流入,右边有常数表示它向汇点流出。网络流能够保证所有的等式成立(因为每个节点的流量平衡),然后再加上费用(A[i] 造成的边的费用对应输入第 i 个数),跑最大费用最大流就好了。

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cctype>
    #include <algorithm>
    #include <queue>
    using namespace std;
    
    int read() {
    	int x = 0, f = 1; char c = getchar();
    	while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
    	while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
    	return x * f;
    }
    
    #define maxn 1010
    #define maxm 4010
    #define oo 2147483647
    #define ool (1ll << 60)
    #define LL long long
    
    struct Edge {
    	int from, to, flow; LL cost;
    	Edge() {}
    	Edge(int _1, int _2, int _3, LL _4): from(_1), to(_2), flow(_3), cost(_4) {}
    };
    struct ZKW {
    	int n, m, s, t, head[maxn], nxt[maxm];
    	LL cost, ans;
    	Edge es[maxm];
    	LL d[maxn];
    	deque <int> Q;
    	bool inq[maxn], vis[maxn];
    	
    	void init() {
    		m = 0; memset(head, -1, sizeof(head));
    		return ;
    	}
    	void setn(int _) { n = _; return ; }
    	
    	void AddEdge(int a, int b, int c, LL d) {
    		es[m] = Edge(a, b, c, d); nxt[m] = head[a]; head[a] = m++;
    		es[m] = Edge(b, a, 0, -d); nxt[m] = head[b]; head[b] = m++;
    		return ;
    	}
    	
    	bool BFS() {
    		memset(inq, 0, sizeof(inq));
    		for(int i = 1; i <= n; i++) d[i] = -ool;
    		d[t] = 0;
    		Q.push_front(t); inq[t] = 1;
    		while(!Q.empty()) {
    			int u = Q.front(); Q.pop_front(); inq[u] = 0;
    			for(int i = head[u]; i != -1; i = nxt[i]) {
    				Edge& e = es[i^1];
    				if(e.flow && d[e.from] < d[u] + e.cost) {
    					d[e.from] = d[u] + e.cost;
    					if(!inq[e.from]) {
    						if(Q.empty() || d[e.from] >= d[Q.front()]) Q.push_front(e.from);
    						else Q.push_back(e.from);
    						inq[e.from] = 1;
    					}
    				}
    			}
    		}
    		if(d[s] == -ool) return 0;
    		for(int i = 0; i < m; i++) es[i].cost += d[es[i].to] - d[es[i].from];
    		cost += d[s];
    		return 1;
    	}
    	
    	int DFS(int u, int a) {
    		if(u == t || !a){ ans += cost * a; return a; }
    		vis[u] = 1;
    		int flow = 0, f;
    		for(int i = head[u]; i != -1; i = nxt[i]) {
    			Edge& e = es[i];
    			if(!vis[e.to] && e.flow && !e.cost && (f = DFS(e.to, min(a, e.flow)))) {
    				flow += f; a -= f;
    				e.flow -= f; es[i^1].flow += f;
    				if(!a) return flow;
    			}
    		}
    		return flow;
    	}
    	
    	int MaxFlow(int _s, int _t) {
    		s = _s; t = _t;
    		int flow = 0, f;
    		while(BFS())
    			do {
    				memset(vis, 0, sizeof(vis));
    				f = DFS(s, oo); flow += f;
    			} while(f);
    		return flow;
    	}
    } sol;
    
    int Cnt, val[maxn];
    struct Node {
    	int id;
    	Node(): id(0) {}
    	int p() { return id ? id : id = ++Cnt; }
    } ns[maxn], Source, Tank;
    
    int main() {
    	int n = read(), m = read(), k = read();
    	for(int i = 1; i <= n; i++) val[i] = read();
    	
    	sol.init();
    	for(int i = 1; i <= n - m; i++) {
    		if(i > m) sol.AddEdge(ns[i].p(), ns[i-m].p(), 1, val[i]);
    		if(i > 1) sol.AddEdge(ns[i].p(), ns[i-1].p(), oo, 0);
    	}
    	for(int i = 1; i <= min(m, n - m); i++) sol.AddEdge(ns[i].p(), ns[n-m+1].p(), 1, val[i]);
    	sol.AddEdge(ns[1].p(), ns[n-m+1].p(), oo, 0);
    	for(int i = max(n - (m << 1) + 1, 1); i <= n - m; i++) sol.AddEdge(ns[n-m+2].p(), ns[i].p(), 1, val[i+m]);
    	sol.AddEdge(ns[n-m+2].p(), ns[n-m].p(), oo, 0);
    	for(int i = n - m + 1; i <= m; i++) sol.AddEdge(ns[n-m+2].p(), ns[n-m+1].p(), 1, val[i]);
    	sol.AddEdge(Source.p(), ns[n-m+2].p(), k, 0);
    	sol.AddEdge(ns[n-m+1].p(), Tank.p(), k, 0);
    	sol.setn(Cnt);
    	
    	sol.MaxFlow(Source.p(), Tank.p());
    	printf("%lld
    ", sol.ans);
    	
    	return 0;
    }
    
  • 相关阅读:
    i++循环与i–循环的执行效率
    嵌入式linux通用截图工具
    imgsed发布
    Embedded Linux From Scratch
    WordPress Plupload插件未明跨站脚本漏洞
    Microsoft Internet Explorer 信息泄露漏洞
    WordPress 多个安全漏洞
    dedecms plus/search.php 注入漏洞利用EXP
    JBoss Enterprise Portal Platform多个跨站脚本执行漏洞
    WordPress organizer/page/users.php脚本多个跨站脚本漏洞
  • 原文地址:https://www.cnblogs.com/xiao-ju-ruo-xjr/p/6728491.html
Copyright © 2011-2022 走看看