int t, n, k, p, v[55][35]; // 缓存 dfs 结果 map<int, map<int, int>> m;
intdfs(int stack_no, int p){ if (m.count(stack_no) && m[stack_no].count(p)) { return m[stack_no][p]; }
if (p == 0) return0; if (stack_no == n - 1) return v[stack_no][min(p - 1, k - 1)];
int res = 0; // i 表示第 stack_no 叠盘子选择的盘子总数 for (int i = 0; i <= min(p, k); i++) { // value 表示此次选择带来的收益价值 int value = 0; if (i != 0) { value = v[stack_no][i - 1]; }
res = max(res, dfs(stack_no + 1, p - i) + value); }
m[stack_no][p] = res; return res; }
intsolve(){ // Prefix sum calculation for (int a = 0; a < n; a++) { for (int b = 0; b < k; b++) { if (b != 0) { v[a][b] = v[a][b - 1] + v[a][b]; } } } // DFS return dfs(0, p); }
intmain(){ cin >> t; for (int i = 1; i <= t; i++) { m.clear(); cin >> n >> k >> p; for (int a = 0; a < n; a++) { for (int b = 0; b < k; b++) { cin >> v[a][b]; } } printf("Case #%d: %d\n", i, solve()); } return0; }
C. Workout
题目大意
N 次锻炼,第 i 次锻炼时间为 Mi,时间单调递增,定义最大的相邻时间差为锻炼难度,在 N 次锻炼中插入 K 次新的锻炼(保持单调递增),使得难度尽量小,求最小的难度值。
锻炼时长 Mi, Mi+1 需要变为难度 d 至少需要插入 ⌈dMi+1−Mi−1⌉ 个新的锻炼。
代码 2
#include<iostream>
usingnamespacestd;
int t, n, k, m[100005], max_diff; // 单个间隔降到难度 d 至少需要的插入个数 intsingle_insert_num(int delta_m, int d){ int cnt = 0, tmp = 0; while (tmp < delta_m) { cnt++; tmp += d; } return cnt - 1; }
// 总体降到难度 d 至少需要的插入个数 inttotal_insert_num(int d){ int res = 0; // 总共有 n - 1 个间隔 for (int i = 0; i < n - 1; i++) { res += single_insert_num(m[i], d); } return res; }
intsolve(){ int low = 1, high = max_diff, res = max_diff; while (low <= high) { int mid = (low + high) / 2; int k_prime = total_insert_num(mid); if (k_prime > k) { low = mid + 1; } else { res = mid; high = mid - 1; } } return res; }
intmain(){ cin >> t; for (int i = 1; i <= t; i++) { max_diff = 0; cin >> n >> k; int prev, cur; for (int i = 0; i < n; i++) { cin >> cur; if (i != 0) { m[i - 1] = cur - prev; max_diff = max(max_diff, m[i - 1]); } prev = cur; } printf("Case #%d: %d\n", i, solve()); } return0; }
D. Bundling
题目大意
将 N 个大写字符串分组,每个组的有 K 个字符串(输入保证 K 整除 N),每个组的得分为这个组的公共前缀长度,求最大的得分总和。