Problem Description
Alice 和 Bob 准备 solo 一场算法竞赛。
比赛一共有 nn 个题,编号为 1,2…,n1,2…,n,对于第 ii 道题,Alice 需要 a[i]a[i] 分钟写出一份正确的代码,Bob 需要 b[i]b[i] 分钟写出一份正确的代码。
比赛规则为
每道题第一个通过的人积 1 分,如果两人同时 AC 该题,只有 Alice 得分。
比赛时长为 10 ^ {18}10
18
分钟。
Alice 和 Bob 的比赛策略都满足:决定要去做某道题后,会一直解决该题,直到自己或者对手 AC 此题,如果对手 AC 该题,则会立即放弃这题。
Bob 写完一份正确的代码后会立即提交,但 Alice 写完一份正确的代码,可以先暂时不交题,等之后再交(交题的时间忽略不计,任何时间都可以交题)。
另外 Alice 知道 Bob 是按 1,2,…,n1,2,…,n 的顺序来依次做题,知道每道题自己需要的时间和 Bob 需要的时间(即 aa 序列和 bb 序列)。
输出 Alice 最优策略下最多得几分。
Alice 和 Bob 想题都不需要时间。
Input
第一行一个整数 t(1 \leq t \leq 10)t(1≤t≤10) 表示 tt 组数据。
每组数据第一行一个整数 n (1 \leq n \leq 2000)n(1≤n≤2000) 表示题数。
第二行 nn 个整数,表示 a[1],a[2],…a[n](1 \leq a[i] \leq 1000000000)a[1],a[2],…an。
第三行 nn 个整数,表示 b[1],b[2],…b[n](1 \leq b[i] \leq 1000000000)b[1],b[2],…bn。
保证至多只有一组数据 n>100n>100。
Output
对于每组数据,一行一个整数表示答案。
Sample Input
2
6
6 6 6 6 6 6
1 1 1 1 1 1
3
1 2 3
5 1 1
Sample Output
1
3
样例解释
Case 1 开场直接 rush 最后一题。
Case 2 [0,1) 写掉第一题,第 5 分钟交;[1,3) 写第二题第 6 分钟交,[3,6) 写第三题第 6 分钟交。
思路:
博弈dp个人感觉都是最后都得归结到一个人的决策上去。
本题的B实际就可以当做他是一直在写题,因为A题写完前面的题可以囤起来,等B刚好写完的时候再交。
考虑只有一道题,如果 a [ 1 ] ≤ b [ 1 ] a[1]≤b[1] a[1]≤b[1],A就可以拿到1分,否则0分。
考虑只有两道题,如果 a [ 1 ] + a [ 2 ] ≤ b [ 1 ] + b [ 2 ] a[1]+a[2]≤b[1]+b[2] a[1]+a[2]≤b[1]+b[2],则A可以拿到两分。如果 a [ 2 ] ≤ b [ 1 ] + b [ 2 ] a[2]≤b[1]+b[2] a[2]≤b[1]+b[2]或者 a [ 1 ] ≤ b [ 1 ] a[1]≤b[1] a[1]≤b[1]或者,则可以拿到1分。否则拿不到分。
所以问题可以简化为前i道题,A题可以写掉哪些题。那么转移就是对于第 i i i道题写或者不写。
则可以定义 f [ i ] [ j ] f[i][j] f[i][j]为前i道题A可以拿j道题分的最小时间。那么只要 f [ i − 1 ] [ j − 1 ] + a [ i ] ≤ b [ 1 ] + . . . + b [ i ] f[i-1][j-1]+a[i]≤b[1]+...+b[i] f[i−1][j−1]+a[i]≤b[1]+...+b[i],那就可以拿到第 i i i道题的分。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
typedef long long ll;
using namespace std;
const int maxn = 2e3 + 7;
const ll INF = 0x3f3f3f3f3f3f3f3f;
ll f[maxn][maxn];
ll a[maxn],b[maxn];
ll sum[maxn];
int main() {
int T;scanf("%d",&T);
while(T--) {
int n;scanf("%d",&n);
for(int i = 1;i <= n;i++) {
scanf("%lld",&a[i]);
}
for(int i = 1;i <= n;i++) {
scanf("%lld",&b[i]);
sum[i] = sum[i - 1] + b[i];
}
memset(f,0x3f,sizeof(f));
for(int i = 0;i <= n;i++) {
f[i][0] = 0;
}
for(int i = 1;i <= n;i++) {
for(int j = 1;j <= i;j++) {
if(a[i] + f[i - 1][j - 1] <= sum[i]) {
f[i][j] = f[i - 1][j - 1] + a[i];
}
f[i][j] = min(f[i][j],f[i - 1][j]);
}
}
for(int i = n;i >= 0;i--) {
if(f[n][i] != INF) {
printf("%d\n",i);
break;
}
}
}
return 0;
}