oldssoj2674Delicious Apples(离散+贪心+环上折半dp)
2015-08-25 20:55
357 查看
题目描述
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.
输入
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.
输出
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即可。
评价:思想很巧妙。离散的处理
相关文章推荐
- Android-基本控件(Toast 全解)
- Appium源码分析(六)-find(上)
- Android中asset文件夹和raw文件夹区别
- [Android]代码实现ColorStateList及StateListDrawable
- Android学习 之 ColorStateList按钮文字变色
- IOS上传文件开发
- Android控件之ListView
- Android帧率测试
- 【Cocos2dx】使用CCControlButton创建按钮、按钮点击事件,点击事件中的组件获取,setPosition的坐标问题
- Android-基本控件(Ratingbar 实现)
- 学习IOS中
- Android的重要控件ListView的诸多问题处理方案
- iOS 时间戳转换为时间
- Android-实现简单画图画板
- Android学习之Intent过滤器的使用
- iOS 宏(define)与常量(const)的正确使用
- 【读书笔记】iOS-读取文本文件
- iOS中Block介绍(一)基础
- Objective-C 苹果开发文档 10 Conventions
- 【读书笔记】iOS-读取文本文件