HDU-5037-Frog

原题
Once upon a time, there is a little frog called Matt. One day, he came to a river.
The river could be considered as an axis.Matt is standing on the left bank now (at position 0). He wants to cross the river, reach the right bank (at position M). But Matt could only jump for at most L units, for example from 0 to L.
As the God of Nature, you must save this poor frog.There are N rocks lying in the river initially. The size of the rock is negligible. So it can be indicated by a point in the axis. Matt can jump to or from a rock as well as the bank.
You don’t want to make the things that easy. So you will put some new rocks into the river such that Matt could jump over the river in maximal steps.And you don’t care the number of rocks you add since you are the God.
Note that Matt is so clever that he always choose the optimal way after you put down all the rocks.
Input
The first line contains only one integer T, which indicates the number of test cases.
For each test case, the first line contains N, M, L (0<=N<=2*105,1<=M<=109, 1<=L<=10^9).
And in the following N lines, each line contains one integer within (0, M) indicating the position of rock.
Output
For each test case, just output one line “Case #x: y", where x is the case number (starting from 1) and y is the maximal number of steps Matt should jump.
Sample Input
2
1 10 5
5
2 10 3
3
6
Sample Output
Case #1: 2
Case #2: 4
题意:
有一只叫matt的青蛙要过宽度为m的河,河上已经存在n个石头,小青蛙只能跳在石头上或者岸上,但是小青蛙会选择跳的次数最少的方式去跳。你可以随意的在河中间加石头,目的是为了让小青蛙多跳几次。现在需求小青蛙最多跳多少次?
题解:
既然想让小青蛙多跳,小青蛙又只能跳L,那么如果我每一次都让他跳L+1的距离,那么它必然要跳两次。
为什么挑选L+1呢?
挑选<=L的情况小青蛙只需要1次,挑选L+x(1<x<L)那么相比L+1必然会浪费掉x-1的距离。所以挑选L+1的既能让小青蛙多跳一次。注意此处加石头一定实在原有相邻两个石头之间。
那么如果原有的两个石头之间的距离小于L怎么办呢?
因为小青蛙会挑选最好的方法,所以这么短一点的距离他不会跳,可以攒着。因为你可以随意加石头,让小青蛙跳得更远所以这段距离可以一直攒着,直到攒着的这段距离也大于L那么也必须要跳一次了。这里也可以省点距离,让小青蛙跳之前还未超过L时的最大攒这距离,这是就又省下一个mod的距离。
文字不是能够很好的描述清楚,这里请读者参考文字和代码仔细理解,认真体会其中的贪心策略。(更多细节见代码)
附上AC代码:

#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
int s[200005];
int main()
{
    //ios::sync_with_stdio(false);
    int t,n,m,l;
    scanf("%d",&t);//cin>>t;
    int cnt=1;//记录case个数
    while(t--)
    {
        scanf("%d%d%d",&n,&m,&l);//cin>>n>>m>>l;
        for(int i=1;i<=n;i++)
            scanf("%d",&s[i]);//cin>>s[i];
        s[0]=0;//第一块石头相当于是0
        s[++n]=m;//最后一块石头相当于是岸边
        sort(s,s+n);//如果输入是无序的则需要排序
        int res=0,dis=l;//初始化跳跃次数为0,第一次跳跃的距离为L
        printf("Case #%d: ",cnt++);//cout<<"Case #"<<cnt++<<":";//注意格式,很容易出错
        for(int i=0;i<n;i++)
        {
			int mod=(s[i+1]-s[i])%(l+1);//记录对L+1取余的结果作为下一次跳跃时需要加上的距离
			int c=(s[i+1]-s[i])/(l+1);//记录两块石头之间有几个L+1
			if(dis+mod>l)//如果下一次跳跃距离超过了L,也就是下一次我需要跳跃的距离大于我能跳的
            {
				dis=mod;//则只跳dis,并且重置dis为mod(这一次跳不玩的留着下一次跳
				res+=(1+2*c);//每一个L+1需要跳两次+由于累计需要跳跃的超过L,必须要跳一次
			}
			else//累计需要跳的不超过L
            {
				dis+=mod;//可以继续累计
				res+=2*c;//只需要跳c*2次
			}
        }
        printf("%d\n",res);//cout<<res<<endl;
    }
    return 0;
}

欢迎评论!

猜你喜欢

转载自blog.csdn.net/wjl_zyl_1314/article/details/83095690