Delicious Apples
Time Limit: 5000/3000 MS (Java/Others) Memory Limit: 524288/524288 K (Java/Others)
Total Submission(s): 1057 Accepted Submission(s): 354
Problem Description
There are n apple trees planted along a cyclic road, which is L metres long. Your storehouse is built at position 0 on that cyclic road.
The ith tree is planted at position xi, clockwise from position 0. There are ai delicious apple(s) on the ith tree.
You only have a basket which can contain at most K apple(s). You are to start from your storehouse, pick all the apples and carry them back to your storehouse using your basket. What is your minimum distance travelled?
1≤n,k≤105,ai≥1,a1+a2+...+an≤105
1≤L≤109
0≤x[i]≤L
There are less than 20 huge testcases, and less than 500 small testcases.
The ith tree is planted at position xi, clockwise from position 0. There are ai delicious apple(s) on the ith tree.
You only have a basket which can contain at most K apple(s). You are to start from your storehouse, pick all the apples and carry them back to your storehouse using your basket. What is your minimum distance travelled?
1≤n,k≤105,ai≥1,a1+a2+...+an≤105
1≤L≤109
0≤x[i]≤L
There are less than 20 huge testcases, and less than 500 small testcases.
Input
First line: t, the number of testcases.
Then t testcases follow. In each testcase:
First line contains three integers, L,n,K.
Next n lines, each line contains xi,ai.
Then t testcases follow. In each testcase:
First line contains three integers, L,n,K.
Next n lines, each line contains xi,ai.
Output
Output total distance in a line for each testcase.
Sample Input
2
10 3 2
2 2
8 2
5 1
10 4 1
2 2
8 2
5 1
0 10000
Sample Output
18
26
Source
解题:核心思想是贪心,关键在于枚举最后剩下的K个苹果。
先把圆分成两半,用sum[i]算出到i最小需要多长路
为什么是sum[i] = sum[i-k] + L[i]呢?
这个其实是倒推!很明显,最后可能从前开始的不足K个,为什么不是从前面推呢?
很明显,无论是从前面推还是后面推,其包含的K长度的区间个数是一定的,
但是从后面推得到好处就是和会更少!
这里体现了传说中的贪心思想。
明显从后面推,前面部分的值更少
最后我们需要枚举K个长度的区间,横跨两个半圆
LL ret = (sum[Lsize][0] + sum[Rsize][1])<<1;
这句话表示纯粹的使用不环绕圆的方式取完所有苹果的最短路径,是的最短,因为前面贪心了嘛。
int a = Lsize - i; 表示的是什么呢?表示从左半圆选择i个 那么剩下的部分不跨圆,继续使用拿完原路返回策略
int b = max(0,Rsize - (K - i)); 剩下的 K- i个采用拿了原路返回的策略
ret = min(ret,((sum[a][0] + sum[b][1])<<1) + Len); 那么这K个,我们采用拿了 不原路返回,采用绕圆的方法
所以多了Len
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long LL; 4 const int maxn = 100010; 5 LL d[maxn],tot,sum[maxn][2]; 6 vector<LL>L,R; 7 int main() { 8 int kase,n,K,m,pos; 9 LL Len; 10 scanf("%d",&kase); 11 while(kase--) { 12 scanf("%d%d%d",&pos,&n,&K); 13 L.clear(); 14 R.clear(); 15 Len = pos; 16 for(int i = tot = 0; i < n; ++i) { 17 scanf("%d%d",&pos,&m); 18 for(int j = 0; j < m; ++j) 19 d[tot++] = pos; 20 } 21 for(int i = 0; i < tot; ++i) { 22 if(d[i]*2 < Len) L.push_back(d[i]); 23 else R.push_back(Len - d[i]); 24 } 25 sort(L.begin(),L.end()); 26 sort(R.begin(),R.end()); 27 int Lsize = L.size(),Rsize = R.size(); 28 sum[0][0] = sum[0][1] = 0; 29 for(int i = 0; i < Lsize; ++i) 30 if(i + 1 <= K) sum[i + 1][0] = L[i]; 31 else sum[i + 1][0] = sum[i - K + 1][0] + L[i]; 32 for(int i = 0; i < Rsize; ++i) 33 if(i + 1 <= K) sum[i+1][1] = R[i]; 34 else sum[i+1][1] = sum[i-K+1][1] + R[i]; 35 LL ret = (sum[Lsize][0] + sum[Rsize][1])<<1; 36 for(int i = 0; i <= Lsize && i <= K; ++i) { 37 int a = Lsize - i; 38 int b = max(0,Rsize - (K - i)); 39 ret = min(ret,((sum[a][0] + sum[b][1])<<1) + Len); 40 } 41 cout<<ret<<endl; 42 } 43 return 0; 44 }