http://acm.hdu.edu.cn/showproblem.php?pid=5303
题意:长度为L的圈上,有n棵苹果树,每次最多摘k个,求把所有苹果树上的苹果都摘回起点0上的最短距离。所有树上的苹果总和不超过1e5.
思路:有点贪心思想,苹果取回,要么取了原路返回,要么绕一圈再回去。但是可以发现,绕一圈的情况最多有一次,从中间平分,左后两边能满k运回去的,一定原路返回优于绕圈,因为有k个的约束,所以还要找到最小的左右原路返回的最小点,然后就可以分析,若存在绕圈的情况时的消耗,取走的一定是中间连续的k个。左右的分别就近原路返回。
感想:一开始也是贪心思想,但是做的方法逻辑性不够清晰,所以一直WA,今天就看了题解,感觉抓住所有苹果数不超过1e5这一点,将问题转化成对于每一个苹果考虑其走向,比较有意思
拓展:数据量不大时,可以考虑一下转换对象。具体题目还没想到~~
代码:
#include<bits/stdc++.h>
using namespace std;
#define mod 1000000007
long long T,n,l,k,a,b;
long long ans,dpl[100005],dpr[100005],poit[100005],ant;
struct AA
{
long long rt,num;
bool operator<(const AA &aa)const
{
return rt<aa.rt;
}
}pos[100050];
int main()
{
scanf("%lld",&T);
while(T--)
{
ant=0;
ans=0;
scanf("%lld%lld%lld",&l,&n,&k);
for(int i=1;i<=n;i++)
{
scanf("%lld%lld",&pos[i].rt,&pos[i].num);
}
sort(pos+1,pos+1+n);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=pos[i].num;j++)
{
poit[++ant]=pos[i].rt;
}
}
int j;
for(int i=1;i<=ant;i++)
{
j=max((long long)0,i-k);
dpl[i]=dpl[j]+poit[i]*2;
}
dpl[ant+1]=dpr[ant+1]=0;
for(int i=ant;i>=1;i--)
{
j=min(i+k,ant+1);
dpr[i]=dpr[j]+(l-poit[i])*2;
}
ans=dpr[1];
for(int i=1;i<=ant;i++)
{
ans=min(ans,dpl[i]+dpr[i+1]);
}
for(int i=0;i+k<=ant;i++)
{
ans=min(ans,dpl[i]+dpr[i+k+1]+l);
}
if(k>ant) ans=min(ans,l);
printf("%lld\n",ans);
}
}