【dtoj#4946】Solo

传送门
来源: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 1t10,1n100,1a[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 1t10,1n2000,1a[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;
}

Thanks!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值