这个题目的意思: 在一个长度为L的环上,0和L位置重叠,在0 - L的某些位置有n个点,每个点有一些苹果数目。现在一个人在0处,有个大小为K的篮子,要求用最小距离把所有苹果全运回0处。
分析:
对于直线上的一些点处,有某些苹果,直接从出发点出发,遇到苹果就装到篮子,装满就回,这样是最优的。(很好证明)
这个题目的特殊之处在于可以绕一圈装K个苹果回到0点
假设左右苹果总数目都大于K , 若进行绕圈,那么只会绕圈一次且个数为K。若多于2K必有一边超过K,那么可以让这K个从一边走,更优,若K<X<2K,那么可以让剩下的X-K从一边走更优。
所以当两边都大于K个时候,那么最多绕圈一次拿K个苹果,且是从中间到两边一段相邻的苹果,这样,直接暴力一下,即可。
其余情况下,就是在考虑绕圈时,要尽可能多的拿,就行了。
#include <set> #include <cstdio> #include <vector> #include <iostream> #include <cstring> #include <queue> #include <map> #include <string> #include<iomanip> #include <algorithm> using namespace std; #define pii(x,y) make_pair(x,y) #define clr(a, x) memset(a, x, sizeof a) #define rep(i,n) for(int i=0;i<(int)n;i++) #define rep1(i,x,y) for(int i=x;i<=(int)y;i++) typedef pair<int,int> pii; typedef long long LL; const int N = 101010; const int inf = 0x3f3f3f3f; struct node{ int x,p; bool operator<(const node& rhs)const{ return p<rhs.p; } }a[N]; int bel[N]; int L,n,K,sum; LL suml(int c){ LL res=0; while(c>=K){ res+=a[bel[c]].p*2; c-=K; } if(c) res+=a[bel[c]].p*2; return res; } LL sumr(int c){ LL res=0; while(sum-c>=K){ res+=(L-a[bel[c+1]].p)*2; c+=K; } if(sum-c>0) res+=(L-a[bel[c+1]].p)*2; return res; } int main() { int T; scanf("%d",&T); while(T--){ scanf("%d %d %d",&L,&n,&K); sum = 0; int l = 0,r = 0; rep1(i,1,n) scanf("%d %d",&a[i].p,&a[i].x); sort(a+1,a+1+n); rep1(i,1,n){ rep1(j,sum+1,sum+a[i].x) bel[j]=i; sum+=a[i].x; if(a[i].p<=L/2){ l = sum; r=sum; } } LL res = suml(l) + sumr(l); for(int i=1;i<K&&i<=l;i++){ res = min(res,suml(l-i)+sumr(min((l-i+K),sum))+L); } cout<<res<<endl; } return 0; }