Codeforces Round #408 (Div. 2) E. Exam Cheating 滚动dp
Zane and Zane's crush have just decided to date! However, the girl is having a problem with her Physics final exam, and needs your help.
There are n questions, numbered from 1 to n. Question i comes before question i + 1 (1 ≤ i < n). Each of the questions cannot be guessed on, due to the huge penalty for wrong answers. The girl luckily sits in the middle of two geniuses, so she is going to cheat.
However, the geniuses have limitations. Each of them may or may not know the answers to some questions. Anyway, it is safe to assume that the answers on their answer sheets are absolutely correct.
To make sure she will not get caught by the proctor, the girl will glance at most p times, each time looking at no more than kconsecutive questions on one of the two geniuses' answer sheet. When the girl looks at some question on an answer sheet, she copies the answer to that question if it is on that answer sheet, or does nothing otherwise.
Help the girl find the maximum number of questions she can get correct.
The first line contains three integers n, p, and k (1 ≤ n, p ≤ 1, 000, 1 ≤ k ≤ min(n, 50)) — the number of questions, the maximum number of times the girl can glance, and the maximum number of consecutive questions that can be looked at in one time glancing, respectively.
The second line starts with one integer r (0 ≤ r ≤ n), denoting the number of questions the first genius has answered on his answer sheet. Then follow r integers a1, a2, ..., ar (1 ≤ ai ≤ n) — the answered questions, given in a strictly-increasing order (that is, ai < ai + 1).
The third line starts with one integer s (0 ≤ s ≤ n), denoting the number of questions the second genius has answered on his answer sheet. Then follow s integers b1, b2, ..., bs (1 ≤ bi ≤ n) — the answered questions, given in a strictly-increasing order (that is, bi < bi + 1).
Print one integer — the maximum number of questions the girl can answer correctly.
题目大意:有一个人要考试作弊, 她可以偷看左右两个人的试卷。但是她只能偷看p次,每次只能看一个人试卷上的连续的k个题目。总共有n道题目,给你左右两个人能做对的题目,求出她最大能做对几道题。
样例解释:第一个样例:她共有2次偷看的机会,每次只能看3道题目,第一次偷看person1的(1,2,3), 第二次偷看person2的(4, 5, 6),可以作对的题目为(1, 3, 5, 6)共4道
解析:这道题目可以看作区间覆盖,你有p个长度(0~k)的线段,尽量覆盖所有的规定的点即correct answer。
我们可以用dp[i][j][x][y]来表示前i道题目使用了j次机会,其中person1还可以偷看连续的x道题目,peison2y道题目。
如果我们现在在当前状态 dp[i][j][x-1][y-1],
对于下一道题目我们可以选择使用对person1一次偷看的机会,会转移到dp[i+1][j+1][k-1][y] + (correct_i?)
或者对person2使用,会转移到dp[i+1][j+1][x][k-1] + (correct_i?)
或者不使用,会转移到dp[i+1][j][x][y] + (correct_i?)
当然开1000*1000*50*50的空间是存不下的,所以要改成滚动数组
另外对于时间的优化,如果我们可以覆盖整个区间(p > 2*ceil(n/k)), 那么我们覆盖最多的次数用2*ceil(n/k)就够了!
时间复杂度 O(n*p*k^2) = O(n*(n/k)*k^2) = O(n^2*k)
#include <bits/stdc++.h> using namespace std; int a[1005], b[1005], dp[2][1005][55][55]; int ab(int x) { if(x > 0) return x; return 0; } int main() { int n, p, k, r1, r2; scanf("%d%d%d", &n, &p, &k); if(p > 2*(n+k-1)/k) p = 2*(n+k-1)/k; scanf("%d", &r1); for(int i = 0, x; i < r1; i++) { scanf("%d", &x); a[x] = 1; } scanf("%d", &r2); for(int i = 0, x; i < r2; i++) { scanf("%d", &x); b[x] = 1; } memset(dp, -0x3f, sizeof(dp)); dp[0][0][0][0] = 0; for(int i = 1; i <= n; i++) { for(int j = 0; j <= p; j++) { for(int x = 0; x < k; x++) { for(int y = 0; y < k; y++) { dp[i&1][j+1][k-1][ab(y-1)] = max(dp[i&1][j+1][k-1][ab(y-1)], dp[~i&1][j][x][y] + (a[i] || (y&&b[i]))); dp[i&1][j+1][ab(x-1)][k-1] = max(dp[i&1][j+1][ab(x-1)][k-1], dp[~i&1][j][x][y] + (b[i] || (x&&a[i]))); dp[i&1][j][ab(x-1)][ab(y-1)] = max(dp[i&1][j][ab(x-1)][ab(y-1)], dp[~i&1][j][x][y] + ((a[i]&&x)||(b[i]&&y))); } } } memset(dp[~i&1], -0x3f, sizeof(dp[~i&1])); } int ans = 0; for(int j = 0; j <= p; j++) { for(int x = 0; x <= k; x++) { for(int y = 0; y <= k; y++) ans = max(dp[n&1][j][x][y], ans); } } printf("%d\n", ans); return 0; }