BZOJ 1283: 序列

1283: 序列

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 272  Solved: 151
[Submit][Status][Discuss]

Description

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

Input

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

Output

最大和。

Sample Input

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

Sample Output

30

HINT

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

Source

[Submit][Status][Discuss]

 

最大费用最大流

 

设立一个源点,一个汇点,源点向1连$<s,1,k,0>$的边(分别是出点,入点,流量,费用),n向汇点连$<n,t,k,0>$的边,1到n也用$<i,i+1,k,0>$的边连起来,限制最多流过k个流量。

1到n每个点$i$向$i+m$连一条$<i,i+m,1,num_{i}>$的边,表示选择这个数字,下次该流最少需要在$i+m$点之后选择下一个选择的数字。如果$i+m \gt n$,就向汇点连。

 

 1 #include <bits/stdc++.h>
 2 
 3 const int inf = 1e9;
 4 const int siz = 20005;
 5 
 6 int n, m, k, num[siz];
 7 
 8 int s, t;
 9 int hd[siz];
10 int to[siz];
11 int fl[siz];
12 int vl[siz];
13 int nt[siz];
14 
15 inline void add(int u, int v, int f, int w)
16 {
17     static int edge = 0, init = 1;
18     if (init)memset(hd, -1, sizeof(hd)), init = 0;
19     nt[edge] = hd[u]; to[edge] = v; fl[edge] = f; vl[edge] = +w; hd[u] = edge++;
20     nt[edge] = hd[v]; to[edge] = u; fl[edge] = 0; vl[edge] = -w; hd[v] = edge++;
21 }
22 
23 int pre[siz];
24 int dis[siz];
25 
26 inline bool spfa(void)
27 {
28     static int que[siz], inq[siz], head, tail;
29     for (int i = s; i <= t; ++i)dis[i] = -inf;
30     memset(inq, 0, sizeof(inq));
31     head = 0, tail = 0;
32     que[tail++] = s;
33     pre[s] = -1;
34     dis[s] = 0;
35     
36     while (head != tail)
37     {
38         int u = que[head++], v; inq[u] = 0;
39         
40         for (int i = hd[u]; ~i; i = nt[i])
41             if (dis[v = to[i]] < dis[u] + vl[i] && fl[i]) {
42                 dis[v] = dis[u] + vl[i], pre[v] = i ^ 1;
43                 if (!inq[v])inq[que[tail++] = v] = 1;
44             }
45     }
46     
47     return dis[t] > -inf;
48 }
49 
50 inline int maxCost(void)
51 {
52     int cost = 0;
53     
54     while (spfa())
55     {
56         int flow = inf;
57         
58         for (int i = pre[t]; ~i; i = pre[to[i]])
59             if (flow > fl[i ^ 1])flow = fl[i ^ 1];
60             
61         for (int i = pre[t]; ~i; i = pre[to[i]])
62             fl[i] += flow, fl[i ^ 1] -= flow;
63             
64         cost += flow * dis[t];
65     }
66     
67     return cost;
68 }
69 
70 signed main(void)
71 {
72     scanf("%d%d%d", &n, &m, &k);
73     
74     for (int i = 1; i <= n; ++i)
75         scanf("%d", num + i);
76         
77     s = 0, t = n + 1;
78     
79     add(s, 1, k, 0);
80     add(n, t, k, 0);
81     
82     for (int i = 1; i < n; ++i)
83         add(i, i + 1, k, 0);
84         
85     for (int i = 1; i <= n; ++i)
86         if (i + m <= n)
87             add(i, i + m, 1, num[i]);
88         else
89             add(i, t, 1, num[i]);
90     
91     printf("%d\n", maxCost());
92 }

 

@Author: YouSiki

 

posted @ 2017-01-11 17:14  YouSiki  阅读(389)  评论(0编辑  收藏  举报