传送门
来源:2020百度之星初赛第二场
题目描述
Alice 和 Bob 准备 solo 一场算法竞赛。
比赛一共有
n
n
n 个题,编号为
1
,
2
,
…
,
n
1,2,\dots,n
1,2,…,n,对于第
i
i
i道题,Alice 需要
a
[
i
]
a[i]
a[i] 分钟写出一份正确的代码,Bob 需要
b
[
i
]
b[i]
b[i] 分钟写出一份正确的代码。
比赛规则为
- 每道题第一个通过的人积 1 分,如果两人同时 AC 该题,只有 Alice 得分。
- 比赛时长为 1 0 18 10 ^ {18} 1018分钟。
Alice 和 Bob 的比赛策略都满足:决定要去做某道题后,会一直解决该题,直到自己或者对手 AC 此题,如果对手 AC 该题,则会立即放弃这题。
Bob 写完一份正确的代码后会立即提交,但 Alice 写完一份正确的代码,可以先暂时不交题,等之后再交(交题的时间忽略不计,任何时间都可以交题)。
另外 Alice 知道 Bob 是按
1
,
2
,
.
.
.
.
,
n
1,2,....,n
1,2,....,n 的顺序来依次做题,知道每道题自己需要的时间和 Bob 需要的时间(即
a
a
a序列和
b
b
b 序列)。
输出 Alice 最优策略下最多得几分。
Alice 和 Bob 想题都不需要时间。
输入格式
第一行一个整数
t
t
t 表示
t
t
t 组数据。
每组数据第一行一个整数
n
n
n 表示题数。
第二行
n
n
n 个整数,表示
a
[
1
]
,
a
[
2
]
,
…
,
a
[
n
]
a[1],a[2],\dots,a[n]
a[1],a[2],…,a[n]。
第三行
n
n
n 个整数,表示
b
[
1
]
,
b
[
2
]
,
…
,
b
[
n
]
b[1],b[2],\dots,b[n]
b[1],b[2],…,b[n]。
输出格式
对于每组数据,一行一个整数表示答案。
样例输入
2
6
6 6 6 6 6 6
1 1 1 1 1 1
3
1 2 3
5 1 1
样例输出
1
3
样例解释
Case 1 开场直接 rush 最后一题。
Case 2
[
0
,
1
)
[0,1)
[0,1) 写掉第一题,第
5
5
5 分钟交;
[
1
,
3
)
[1,3)
[1,3) 写第二题第
6
6
6 分钟交,
[
3
,
6
)
[3,6)
[3,6) 写第三题第
6
6
6 分钟交。
数据范围与提示
对于
50
%
50\%
50% 的数据,
1
≤
t
≤
10
,
1
≤
∑
n
≤
100
,
1
≤
a
[
i
]
,
b
[
i
]
≤
1
0
4
1 \leq t \leq 10,1\leq \sum n \leq 100,1\leq a[i],b[i] \leq 10^4
1≤t≤10,1≤∑n≤100,1≤a[i],b[i]≤104。
对于
100
%
100\%
100% 的数据,
1
≤
t
≤
10
,
1
≤
∑
n
≤
2000
,
1
≤
a
[
i
]
,
b
[
i
]
≤
1
0
9
1 \leq t \leq 10,1\leq \sum n \leq 2000,1\leq a[i],b[i] \leq 10^9
1≤t≤10,1≤∑n≤2000,1≤a[i],b[i]≤109。
题解
显而易见的是,对于同一道题Alice必和Bob同时提交,好让Bob做题的进度尽可能慢。这样Bob做完每道题的时间就成为了一个固定的限制条件,Alice必须在这个时间之前做完这道题。
由题面可以想到dp。由于时间范围很大,时间不能作为dp的维度,但可以作为dp的内容。即,dp[i][j]为对于前i题得到j分所花费的时间(令花费的时间最少一定最优)。最后在dp[n]中找到有可能(时间<inf)的最大答案即可。
代码:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
int tmp;
int t,n,a[2005],b[2005],score;
long long sch[2005],dp[2005][2005];
int main(){
scanf("%d",&t);
for(int i=1;i<=t;i++){
scanf("%d",&n);
sch[0]=0;
score=0;
for(int j=1;j<=n;j++) scanf("%d",&a[j]);
for(int j=1;j<=n;j++){
scanf("%d",&b[j]);
sch[j]=sch[j-1]+b[j];//Bob做完这道题需要的时间
}
for(int j=0;j<=n;j++){
dp[j][0]=0;
for(int k=1;k<=n;k++) dp[j][k]=1e18;
}
for(int j=1;j<=n;j++){//题数
for(int k=1;k<=j;k++){//分数
if(dp[j-1][k-1]+a[j]<=sch[j]){
dp[j][k]=dp[j-1][k-1]+a[j];//先看能不能得到这道题的分数,再看得到这题分数之后是不是有必要得它
}
dp[j][k]=min(dp[j][k],dp[j-1][k]);
}
}
for(int j=n;j>=0;j--){
if(dp[n][j]<1e18){
score=j;
break;
}
}
printf("%d\n",score);
}
return 0;
}