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;
    }
    
  • 相关阅读:
    webbrowser获取页面文章指定段落内容
    webbrowser防止弹窗(IE)
    webbrowser模拟手动输入
    WPF加载Winform窗体时 报错:子控件不能为顶级窗体
    FAQs: 我们可以在那里来为我的没有提升管理权限的应用程序存储用户数据?
    Winform中修改WebBrowser控件User-Agent的方法(已经测试成功)
    必应代码搜索 Bing Code Search 安装
    Microsoft Visual Studio Professional 2012 专业版 下载
    vs2012 aspx 没有设计视图了?
    vs2010 Express 下载连接
  • 原文地址:https://www.cnblogs.com/xiao-ju-ruo-xjr/p/6728491.html
Copyright © 2011-2022 走看看