解题报告 之 HDU5303 Delicious Apples
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 i-th tree is planted at position xi, clockwise from position 0. There are ai delicious apple(s) on the i-th 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?
The i-th tree is planted at position xi, clockwise from position 0. There are ai delicious apple(s) on the i-th 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?
There are less than 20 huge testcases, and less than 500 small testcases.
Input
First line: t ,
the number of testcases.
Thent testcases
follow. In each testcase:
First line contains three integers,L,n,K .
Nextn lines,
each line contains xi,ai .
Then
First line contains three integers,
Next
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
圈上有n个苹果树(给出位置),每棵树下有一定数量的苹果。你有一个能装K个苹果的框子。如今你要将全部苹果运到你所在的位置。问你最少走多少路?
分析:第一点非常easy想到,离起点左右非常近的苹果更倾向于选择原路返回更省。而靠近中间的苹果有可能打包绕一圈再回来更省。
那么问题来了?这个“中间”究竟如何才算中间呢,这个点就是这个题的精髓。
大家能够把这个中间想成一个区间,问题的难点就转化为了怎么选择这个区间。也就是我们要决定选择哪些苹果绕一圈打包回来更省。
这的确是一个难解决的问题。。也是本题巧妙的地方。我们枚举究竟要把那些苹果绕一圈打包带回。我们把一个一个苹果离散出来而不再以苹果树作为考虑对象。并把这些苹果划分为更靠近左边和更靠近右边的。那么我们要枚举的就是,要从左边拿多少个(无疑是最远的那几个)到绕一圈的这个框中。
注意重点在于,从左边最多取K个,也就是仅仅有最后一筐可能须要绕一圈。由于假设从左边取超过K个。那么我们全然能够先取K个依照原路返回的方法(路程一定<=L),那之后问题终于回归不超过K个。
我们枚举的实质事实上在尝试一种平衡局面,使得左右两边选择原路返回路线的框能够尽量利用充分,而不要出现有一趟原路返回仅仅装1、2个苹果。
上代码:
#include<iostream> #include<algorithm> #include<cstdio> #include<vector> #include<cstring> using namespace std; typedef long long ll; const int MAXN = 1e5 + 10; ll loc[MAXN]; ll disl[MAXN], disr[MAXN];//依照原路返回策略取完第i个苹果所走的路程 ll ans, L, n, k, cnt; vector<ll> lloc, rloc; //存储从左右数的苹果位置 int main() { int kase; scanf( "%d", &kase ); while(kase--) { memset( disl, 0, sizeof disl ); memset( disr, 0, sizeof disr ); lloc.clear(); rloc.clear(); cnt = 0; scanf( "%lld%lld%lld", &L, &n, &k ); for(int i = 1; i <= n; i++) { ll location, number; scanf( "%lld%lld", &location, &number ); for(int j = 1; j <= number; j++) //离散化 loc[cnt++] = location; } for(int i = 0; i < cnt; i++) { if(2 * loc[i] < L) lloc.push_back( loc[i] ); else rloc.push_back( L - loc[i] ); }//苹果分边 sort( lloc.begin(), lloc.end() ); sort( rloc.begin(), rloc.end() ); int left = lloc.size(), right = rloc.size(); for(int i = 0; i < left; i++) disl[i + 1] = (i + 1 <= k ? lloc[i] : disl[i + 1 - k] + lloc[i]); for(int i = 0; i < right; i++) disr[i + 1] = (i + 1 <= k ? rloc[i] : disr[i + 1 - k] + rloc[i]); ans = (disl[left] + disr[right]) * 2; //不绕一圈的情况,不要忘了 for(int i = 0; i <= left&&i <= k; i++)//枚举绕一圈的那框从左边取多少 { ll pickl = left - i; ll pickr = right - (k - i); ans = min( ans, 2 * (disl[pickl] + disr[pickr]) + L ); } printf( "%lld ", ans ); } return 0; }