Larkin’s NOI
Larkin’s NOI
Problem Description
Larkin has been to Yantai to take part in NOI 2010!众所周知(do you know?),NOI比赛中有两类题目:传统试题(就是你们现在正在做的这类)和提交答案型试题(就是给你输入文件,要你给出输出文件的题目)。不妨假设NOI的传统试题都没有部分分,也就是说,必须花费一定的时间才能获得那道题目的满分,否则就1分也拿不到。而对于提交答案型试题,由于测试点很多而且有部分分,所以每做一分钟就可以得到一些分数(当然提交答案型试题也有满分,你是不可能获得比满分更多的分数的)。Unfortunately,NOI比赛时间有限,而Larkin没有足够能力拿到NOI所有题的满分(really?),因此他想请你帮他计算一下,他最多能得到多少分数。
Input
第一行三个整数N,M,T,分别为传统试题的个数、提交答案型试题的个数和NOI考试的时间。
下接N行,每行两个正整数,分别代表这道传统试题需要的时间和它的满分输入保证不会有题目的满分为0分,而且不会有题目需要的时间为0。
最后M行,每行两个正整数,分别代表这道提交答案型试题做1分钟可以获得的分数和它的满分。输入保证这M行中第二个数均为第一个数的倍数,而且不会有题目的满分为0分。
N <= 500,M <= 100000, T <= 10000., (这里绝对不是 T <= 10000, 至少测试数据到了100000)
下接N行,每行两个正整数,分别代表这道传统试题需要的时间和它的满分输入保证不会有题目的满分为0分,而且不会有题目需要的时间为0。
最后M行,每行两个正整数,分别代表这道提交答案型试题做1分钟可以获得的分数和它的满分。输入保证这M行中第二个数均为第一个数的倍数,而且不会有题目的满分为0分。
N <= 500,M <= 100000, T <= 10000., (这里绝对不是 T <= 10000, 至少测试数据到了100000)
Output
一个正整数,为Larkin最多能获得的分数(obviously full score!)。
Sample Input
3 0 100 1 100 100 200 101 10000
Sample Output
200 样例1解释 全部试题都是传统试题,最优策略为做完第二题,然后就没有时间了。获得的分数为200。(no full score?) 样例2输入 3 1 100 1 102 100 200 101 10000 1 99 样例2输出 201 样例2解释 有三道传统试题和一道提交答案型试题。如果仍然做第2道传统试题,那么得分为200。 而如果先做完第1道传统试题,再花费99分钟做提交答案型试题,获得99分,那么总得分为102+99=201分。(no full score again?) 样例3输入 3 1 100 1 102 100 200 101 10000 1 97 样例3输出 200 样例3解释 有三道传统试题和一道提交答案型试题。如果仍先做完第1道传统试题, 再花费97分钟做提交答案型试题(不能像第2个样例一样花费99分钟,因为那道题满分只有97分),获得97分,那么总得分为102+97=199分。 但如果做第二道传统试题,那么获得的分数为200分。(still no full score?) 样例4输入 3 1 10000 1 100 100 200 101 10000 1 100 样例4输出 10400 样例4解释 不解释……(full score… my favorite…)
解释:
这个题目的意思就是说呢,有两种拿分的题目,一种是分数可以一次拿完,但是要花费一定的时间,另一种是做多长时间,拿相应的分,直到这个题的满分,可以一分钟一分钟的拿分。最开始呢,我认为可能是一个贪心的题目,安装题目分数的权值来贪心,然后发现这个权值找不到。有两种题目,不能权值按照同一标准来。然后就越看越像 多重背包,如果不是题目测试数据中的 T 不是题目给定的 T <= 10000. 那么我多重背包还真的可以过,一次出 运行错误,我就很懵,然后在有除法的地方加了判断,还是 运行错误, 于是我又在 下标的地方做了判断,还是 运行错误, 这个时候我就很懵了。之后我们想到,可不可能是 T 的范围不对,毕竟看M的范围都那么大了,T应该要更大才合理。于是 按照 T >= 10000 的思路去写,一开始没想那么多,就直接又变成超时了,就很难受,就开始优化,各种小细节优化,然而并没有用,常数级的优化,终究还是抵不过数量级的优化。然后重新想。
因为第二种地题目是按照一分钟一分钟的来给分的。那么我先做分高的,再做分低的,那就可以了。并且前面 N 不是很大。所以,我就把第一种题目用01背包来做,多余的空间做第二种题,用贪心来填,再找最大的。
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 const int N = 500+100010; 5 6 struct edge { 7 int v, w, s; 8 }edges[N]; 9 10 int ans[N]; 11 12 int Scan() { //输入外挂 13 int res = 0, ch, flag = 0; 14 if ((ch = getchar()) == '-') 15 flag = 1; 16 else if (ch >= '0' && ch <= '9') 17 res = ch - '0'; 18 while ((ch = getchar()) >= '0' && ch <= '9') 19 res = res * 10 + ch - '0'; 20 return flag ? -res : res; 21 } 22 23 struct edge temp[N]; 24 25 bool cmp(edge a, edge b) { 26 return a.w > b.w; 27 } 28 29 int res[N]; 30 31 int main() { 32 int n, m, t; 33 34 while (~scanf("%d %d %d", &n, &m, &t)) { 35 memset(ans, 0, sizeof(ans)); 36 int tn = 1; 37 for (int i = 1; i <= n; i++) { 38 edges[tn].v = Scan(); edges[tn].w = Scan(); edges[tn].s = 1; 39 if (edges[tn].v <= t) tn++; 40 } 41 ans[0] = 0; 42 for (int i = 1; i < tn; i++) { 43 for (int j = t; j >= edges[i].v; j--) { 44 ans[j] = max (ans[j], ans[j - edges[i].v] + edges[i].w); 45 } 46 } 47 48 for (int i = 0; i < m; i++) { 49 temp[i].w = Scan(); temp[i].s = Scan(); 50 } 51 sort(temp, temp + m, cmp); 52 res[0] = 0; 53 int tm = 1; 54 for (int i = 0; i < m && tm <= t; i++) { 55 int tx = temp[i].s / temp[i].w; 56 for (int j = 1; j <= tx && tm <= t; j++) { 57 res[tm] = res[tm - 1] + temp[i].w; 58 tm++; 59 } 60 } 61 62 while(tm <= t) res[tm] = res[tm-1], tm++; 63 64 int max_res = 0; 65 for (int i = 0; i <= t; i++) { 66 int tr = ans[i] + res[t - i]; 67 max_res = max(max_res, tr); 68 } 69 70 printf("%d\n", max_res); 71 } 72 return 0; 73 }