题目描述
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.
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.
1≤L≤109
0≤x[i]≤L
There are less than 20 huge testcases, and less than 500 small testcases.
输入
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 total distance in a line for each testcase.
样例输入
210 3 22 28 25 110 4 12 28 25 10 10000
样例输出
1826
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#define ll long long
using namespace std;
const int maxn=100005;
int n,len,k;
ll dpl[maxn],dpr[maxn],posl[maxn],posr[maxn],l,r,ans;
inline int get(){
char c;while(!isdigit(c=getchar()));
int v=c-48;while(isdigit(c=getchar()))v=v*10+c-48;
return v;
}
int main(){
int t=get();
while(t--){
memset(dpl,0,sizeof(dpl));
memset(dpr,0,sizeof(dpr));
memset(posl,0,sizeof(posl));
memset(posr,0,sizeof(posr));
len=get();n=get();k=get();
l=0;r=0;
for(int i=1;i<=n;++i){
int pos,num;
pos=get();num=get();
if((pos<<1)<=len)while(num--)posl[++l]=pos; //把左边的苹果离散
else while(num--)posr[++r]=len-pos; //把右边的苹果离散
}
sort(posl+1,posl+1+l);
sort(posr+1,posr+1+r);
for(int i=1;i<=l;++i){
if(i<=k)dpl[i]=posl[i];else dpl[i]=dpl[i-k]+posl[i]; //取前i个的最短路程和
}
for(int i=1;i<=r;++i){
if(i<=k)dpr[i]=posr[i];else dpr[i]=dpr[i-k]+posr[i];
}
ans=(dpl[l]+dpr[r])<<1;
for(int i=1;i<=l && i<=k;++i){
ll Le=l-i,Ri=r-k+i;
ans=min(ans,((dpl[Le]+dpr[Ri])<<1)+len);
}
printf("%lld\n",ans);
}
return 0;
}
思路:取苹果的路径有两种,一种是原路返回,一种是绕一圈。什么时候要绕一圈是本题的关键。我们发现,如果一边能放满篮子,原路返回较优,而绕一圈,是在左右剩下不到k个苹果时,为了避免只拿一点苹果回去造成的浪费。容易发现,绕最多只绕一圈。而绕的这一圈从左侧的尾部和右侧的尾部拿多少是可以枚举的。原路返回可以dp来找最短。取二者的min即可。
评价:思想很巧妙。离散的处理