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 ", ans); 57 return 0; 58 }
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 ", ans); 27 return 0; 28 }
NKOJ 比赛 107 B
题目
A粉刷匠 | |
|
问题描述
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 。