2020百度之星初赛第二场 Solo(博弈DP)

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[i1][j1]+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;
}

你可能感兴趣的:(#,其他比赛题目,#,博弈DP)