动规-某动规专练 Round2 (April, 2018)

A

每个木条可以涂 [1, T] 次,对每个木条先来个区间动规。f[i][x] 表示前 i 个位置涂 x 次的最大收益。

f[i][x] = f[k][x-1] + gain(k, i)

k 取 [x-1, i)

这样的话问题转化为有很多物品,某一个的价值是 f[i][x] 而重量是 x ,另外 f[i][1] 和 f[i][2]...这样 i 相同的物品不能同时取。

所以是一个逆序枚举的背包,也就是不让当前的更新在当前这一轮讨论(讨论 i 号木条)中产生影响。

 

 1 #include <stdio.h>
 2 #include <algorithm>
 3 #include <string.h>
 4 
 5 using namespace std;
 6 
 7 const int _LEN = 70;
 8 
 9 char S[_LEN];
10 int Sum[_LEN];
11 int N, M, T, f[_LEN][2700], diu[2700];
12 
13 void Init()
14 {
15     int tmp = 0;
16     for (int i = 1; i <= M; ++i) {
17         if (S[i] == '1') ++tmp;
18         Sum[i] = tmp;
19     }
20     return;
21 }
22 
23 void DP()
24 {
25     int i, x, k;
26     memset(f, 0, sizeof f);
27     for (x = 1; x <= T; ++x)
28         for (i = 1; i <= M; ++i) {
29             if (x == 1) { f[i][x] = max(Sum[i], i-Sum[i]); continue; }
30             f[i][x] = f[i-1][x];
31             for (k = x-1; k < i; ++k) {
32                 int gain = max(Sum[i]-Sum[k], (i-Sum[i])-(k-Sum[k]));
33                 f[i][x] = max(f[i][x], f[k][x-1] + gain);
34             }
35         }
36     for (i = T; i >= 1; --i)
37         for (x = 1; x <= i; ++x)
38             diu[i] = max(diu[i], diu[i-x] + f[M][x]);
39     
40     return;
41 }
42 
43 int main()
44 {
45 
46     int i, ans;
47     scanf("%d%d%d", &N, &M, &T);
48     for (i = 1; i <= N; ++i) {
49         scanf("%s", S+1);
50         Init();
51         DP();
52     }
53     
54     ans = 0;
55     for (i = 1; i <= T; ++i) ans = max(ans, diu[i]);
56     printf("%d\n", ans);
57     return 0;
58 }
View Code

 

NKOJ 比赛 107 A

 

状态是这样的: f[i][x] 表示前 i 个位置最小改变次数,当前位置 i 的字符是 x 。

f[i][x] = f[i-1][y] + (x != S[i])

x != y,然后 S[i] 是原字符串的第 i 个位置的字符。

括号里面是说,如果成立值就为 1 ,否则为 0.

 

 1 #include <stdio.h>
 2 #include <algorithm>
 3 
 4 using namespace std;
 5 
 6 int f[120005][30];
 7 char S[120005];
 8 
 9 int main()
10 {
11     int ans, i, x, y, N, M;
12     scanf("%d%d%s", &N, &M, S+1);
13     for (i = 0; i < M; ++i)
14         f[1][i] = (i == S[1]-'A') ? 0 : 1;
15     for (i = 2; i <= N; ++i)
16         for (x = 0; x < M; ++x) {
17             f[i][x] = i;
18             for (y = 0; y < M; ++y) {
19                 if (x == y) continue;
20                 f[i][x] = min(f[i][x], f[i-1][y] + (x != S[i]-'A'));
21             }
22         }
23     ans = N;
24     for (i = 0; i < M; ++i)
25         ans = min(ans, f[N][i]);
26     printf("%d\n", ans);
27     return 0;
28 }
View Code

 

 

NKOJ 比赛 107 B

题目

A粉刷匠
时间限制 : 20000 MS   空间限制 : 65536 KB
问题描述

windy有 N 条木板需要被粉刷。
每条木板被分为 M 个格子。
每个格子要被刷成红色或蓝色。
windy每次粉刷,只能选择一条木板上一段连续的格子,然后涂上一种颜色。
每个格子最多只能被粉刷一次。
如果windy只能粉刷 T 次,他最多能正确粉刷多少格子?
一个格子如果未被粉刷或者被粉刷错颜色,就算错误粉刷。

输入格式

第一行包含三个整数,N M T。
接下来有N行,每行一个长度为M的字符串,'0'表示红色,'1'表示蓝色。

输出格式

一个整数,最多能正确粉刷的格子数。

样例输入 1

3 6 3
111111
000000
001100

样例输出 1

16

样例输入 2

1 50 4
01010110000011100110101000011010100001011001111011

样例输出 2

34

样例输入 3

10 10 10
0011100111
1110110000
1100111110
0111011111
1110000001
0110000011
1011000010
0011010110
1000011001
0100110101

样例输出 3

60

提示

30%的数据,满足 1 <= N,M <= 10 ; 0 <= T <= 100 。
100%的数据,满足 1 <= N,M <= 50 ; 0 <= T <= 2500 。

posted @ 2018-03-23 17:20  derchg  阅读(135)  评论(0编辑  收藏  举报