Hdu3725 Farm 斜率dp+二分

Farm

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 314    Accepted Submission(s): 75


Problem Description
Do you know the "Happy Farm"? It is a very popular webpage game. The player plays the role of the farmer, who can plant vegetables or grow kinds of flowers at his farm. When vegetables or flowers become ripe, the player can get in them in order to make some money. However, the greatest part of the game is to steal other farmers' vegetables and flowers. The owner of the farm can keep a dog to help him guard against theft. Now, Farmer John intends to steal something when his neighbor David isn't online.
Unfortunately, David keeps a dog. Can you work out a best plan for John?

Let's suppose that David has planted n vegetables. The i-th vegetable's value is v i. Meanwhile, stealing the i-th vegetable increases a i anger value of the dog. Due to the Internet and computer conditions, stealing the i-th vegetable will lead to an initial time delay of d i. On the condition that we do not refresh the webpage, if you choose to steal the i-th vegetable in j-th turn, the actual time delay is j * d i. Now, John wants to steal all of the vegetables. He can turn the dog's anger value into zero and restart to count the number of delays by refreshing the webpage. Please pay attention that the value of the vegetable you are stealing now must be less than the value of any other vegetable that you have stolen before. It takes r units of time to refresh the webpage and the game allows you to refresh the webpage for m times at most.

During the whole theft, John wants to keep the maximum anger value of the dog at the lowest level. Meanwhile, the total time it takes cannot be longer than t units. Can you work out a plan?
 
Input
The first line of input contain an integer T (T <= 10), indicating the number of test cases.

Each of the test cases must be organized in the following form. The first line of each case contain four integers n, m, r, t, (1 <= n <= 30000, 1 <= m <= 10, 1 <= r <= 100, 1 <= t <=2 60), with n representing the number of vegetables, m representing the maximum number for you to refresh the page, r representing the time it takes to refresh the page, and t representing the total time for John to commit his crime.

There must be three integers v i, a i, d i, in each of the following n lines.The v i represents the value of each vegetable (just as there are no two same leaves in the world, so are the value of two vegetables).The a i represents the anger value of the dog. And the d i represents the initial delay. 0 < v i <= 5*106, 0 < a i <= 100, n * ∑d i can't be larger than 2 62.
 
Output
The result of the output should be printed in T lines. If there is a solution to the corresponding test case, then print out a positive integer, representing the minimum of the dog's maximum anger value during the whole theft. If John can't steal all the vegetables in the limited time, then the program should print out "I have no idea" in a single line.
 
Sample Input
3 4 1 1 10 4 2 1 3 2 3 1 2 1 2 2 1 4 0 1 13 4 2 1 3 2 3 1 2 1 2 2 1 4 0 1 14 4 2 1 3 2 3 1 2 1 2 2 1
 
Sample Output
6 I have no idea 8
Hint
For the first sample, John steals the first vegetable at the first time and the anger value increases to 2, costing time of 1*1. Then he refresh the webpage, and steals the 2nd ,4th and 3rd vegetable at the second time and the anger value increases to 6, costing time of 1*3+2*1+3*1 and the time of refreshing of 1,which adds to 10 of the total time. Considering that the anger value of the 2nd time comes to the largest, the answer is 6.For the second sample, John cannot refresh the page at all. He must steal the 1st, 2nd, 4th, 3rd in order, and the costing time is 1*1+2*3+3*1+4*1 = 14. Because the total allowed time is 13, so it isimpossible to steal all the vegetables.
 

题意:你要去别人家的“开心农场”偷菜, 每颗菜有三个属性v, d, a(v两两不同).你只能按照v从大到小的顺序偷菜,偷第j颗菜需要j*di的时间,并且主人家的狗的愤怒值会增加ai,但是你可以刷新网页来清空j和狗的愤怒值,刷新一次网页需要时间r,最多刷新m次网页,问能否在时间t内将n颗菜全部偷完并让狗达到的最大愤怒值尽可能小,输出狗达到的最大愤怒值或"*I have no idea*"

 

这题网上都没有题解,我就发一份吧

这题要求最小的a,一开始我想直接dp求a怎么也推不出转移方程,

后来发现只要二分a求最短时间看满不满足条件

求最短时间可以用斜率优化,具体实现看代码

 

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <cstdio>
 4 #include <cstring>
 5 #define LL long long
 6 using namespace std;
 7 
 8 struct node {
 9     int v, a;
10     LL d;
11     bool operator<(const node &rhs) const {
12         return v > rhs.v;
13     } 
14 }vege[30010];
15 
16 int n, m, r, T;
17 int que[30010], head, tail;
18 LL dp[11][30010], sum[30010], nsum[30010], sa[30010], L, R, mid, ans, t;
19 
20 inline LL X(int i) {return i;}
21 inline LL Y(int t, int i) {return dp[t - 1][i] - nsum[i] + i * sum[i];}
22 inline LL A(int i) {return sum[i];}
23 inline LL KX(int a, int b) {return X(a) - X(b);}
24 inline LL KY(int t, int a, int b) {return Y(t, a) - Y(t, b);}
25 
26 bool check(LL mid) {
27     if(nsum[n] <= t && sa[n] <= mid) 
28         return true;
29     memset(dp, -1, sizeof(dp));
30     for(int i = 0; i <= n && sa[i] <= mid; ++i)
31         dp[0][i] = nsum[i];
32     for(int k = 1; k <= m; ++k) {
33         head = tail = 0;
34         if(dp[k - 1][k] != -1)
35             que[tail++] = k;
36         for(int i = k + 1; i <= n; ++i) {
37             while(head < tail && sa[i] - sa[que[head]] > mid)
38                 head++;
39             if(head == tail)
40                 break;
41             while(head + 1 < tail && KY(k, que[head + 1], que[head]) <= A(i) * KX(que[head + 1], que[head])) 
42                 head++;
43             dp[k][i] = Y(k, que[head]) - A(i) * X(que[head]) + nsum[i] + r;
44             if(dp[k - 1][i] != -1) {
45                 while(head + 1 < tail && KY(k, que[tail - 1], que[tail - 2]) * KX(i, que[tail - 1]) >= KY(k, i, que[tail - 1]) * KX(que[tail - 1], que[tail - 2]))
46                     tail--;
47                 que[tail++] = i;
48             }
49         }
50         if(dp[k][n] != -1 && dp[k][n] <= t)
51             return true;
52     }
53     return false;
54 }
55 
56 
57 int main() {
58     for(scanf("%d", &T); T; --T) {
59         sa[0] = sum[0] = nsum[0] = 0;
60         scanf("%d %d %d %lld", &n, &m, &r, &t);
61         for(int i = 1; i <= n; ++i){
62             scanf("%d %d %lld", &vege[i].v, &vege[i].a, &vege[i].d);
63         }
64         sort(vege + 1, vege + n + 1);
65         for(int i = 1; i <= n; ++i) {
66             sum[i] = sum[i - 1] + vege[i].d;
67             nsum[i] = nsum[i - 1] + i * vege[i].d;
68             sa[i] = sa[i - 1] + vege[i].a;
69         }
70         L = 1, R = ans = sa[n] + 1;
71         while(L <= R) {
72             mid = L + R >> 1;
73             if(check(mid)) {
74                 R = mid - 1;
75                 ans = mid;
76             }
77             else 
78                 L = mid + 1;
79         }
80         if(ans == sa[n] + 1)
81             puts("I have no idea");
82         else
83             printf("%lld\n", ans);
84     }
85     return 0;
86 }
View Code

猜你喜欢

转载自www.cnblogs.com/tusikalanse/p/9373811.html