题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5303
题意:有一个长为len(0~len-1)的环,环上一些位置上有苹果树,每棵数上有若干个苹果,有一个大小为k的箩筐,当箩筐满了之后可以回到出发点0处把苹果卸下,问最少走多少距离才可以把所有苹果运回0点呢?
思路:由于是一个环,我们将其分成左右2边处理出取第i个苹果时的最短距离,由于苹果数量小于10^5,将苹果离散化,分别存入l和r这2个数组排序,取该苹果的最短距离disl[i]=dis[i-k]+l[i](右边同理),res=(disl[l.size()]+disr[r.size()])*2
当前没有取的苹果个数小于等于k的时候可能会发生要绕一圈取完所有苹果的情况,因此我们枚举这一种情况res=min(res,(disl[l.size()-i]+disr[r.size()-(k-i)])*2+len),注意r.size()-(k-i)可能小于0
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#define LL long long
using namespace std;
LL pos[100030],disl[100030],disr[100030];
vector <LL> l,r;
int main()
{
int t,len,n,k;
scanf("%d",&t);
while (t--)
{
int num=0;
l.clear();
r.clear();
memset(disl,0,sizeof(disl));
memset(disr,0,sizeof(disr));
scanf("%d%d%d",&len,&n,&k);
for (int i=0;i<n;i++)
{
int tmp1,tmp2;
scanf("%d%d",&tmp1,&tmp2);
while (tmp2--)
{
pos[num++]=tmp1;
}
}
for (int i=0;i<num;i++)
{
if (2*pos[i]<len) l.push_back(pos[i]);
else r.push_back(len-pos[i]);
}
sort(l.begin(),l.end());
sort(r.begin(),r.end());
for (int i=0;i<l.size();i++)
{
if (i+1<=k)
disl[i+1]=l[i];
else
disl[i+1]=disl[i+1-k]+l[i];
}
for (int i=0;i<r.size();i++)
{
if (i+1<=k)
disr[i+1]=r[i];
else
disr[i+1]=disr[i+1-k]+r[i];
}
LL res=(disl[l.size()]+disr[r.size()])*2;
//cout<<disl[l.size()]<<":"<<disr[r.size()]<<endl;
for (int i=0;i<=k && i<=l.size();i++)
{
int tmp1=l.size()-i;
int tmp2=r.size()-(k-i);
if (tmp2<0) tmp2=0;
res=min(res,(disl[tmp1]+disr[tmp2])*2+len);
}
printf("%I64d\n",res);
}
}