oldssoj2674Delicious Apples(离散+贪心+环上折半dp)

5 篇文章 0 订阅
1 篇文章 0 订阅

题目描述

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 x­i, 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即可。


评价:思想很巧妙。离散的处理


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值