HDU 5037 Frog

来源:互联网 发布:shift js按键 编辑:程序博客网 时间:2024/05/23 14:31

题意 :青蛙要过河  即从0到m   最大跳跃距离为L  本来河里有n个石头  现在你要往里加任意数量个石头(要保证青蛙能过去) 之后青蛙开始跳  使青蛙跳的次数最多 求跳跃次数 (青蛙会采取跳跃次数尽量少的方案)

刚开始以为可以青蛙一边跳一边加石头 (样例也说的通)以为是水题 结果wa了(>﹏<) 然后才明白题意 

首先 如果两个石头的间距小于L时  你肯定不用在往中间加石头  因为 青蛙可以选择不跳你加在中间的石头 所以这种情况你加了石头只能会更糟(给了青蛙多一种选择)

重点是当间距大于L时  你往里加石头  比如 当L=4时  上一个石头位置是15   上上个石头 位置是13   下一个石头 位置是22 此时你要往15和22之间加石头 

这时很多人第一直觉是加16  但这样是不行的  因为 青蛙会从13直接到16   

我们 可以从青蛙的角度来看 青蛙只要贪心 每次跳的尽量远就够了 

所以 为了使结果最大 我们不能加一个石头反而使青蛙更跳的更远  即 在青蛙 位于13的情况下  如果你在 16 17 放了石头 青蛙就会不跳15 从而在同等次数的情况下 前进的更多了 所以结论出来了 我们在18的位置加是最好的 所以可以记录当前跳到的点 距离上一个跳过的点的距离 dis 如果 当距离大于L时  可以 先在距当前石头 k+1-dis的位置加一个 然后新加的石头后面 k+1-dis(dis更新过的情况下)位置加  这样循环下去

 但由于m有10的9次方  L最小为1  暴力的一个一个加会T

但是 当原有的2个石头之间距离很大时 要添加多个石头 但因为dis是不断更新的 相邻的2个dis之和为k+1   所以可以对k+1取模 来计算 这里要注意下  直接 取模得到数字 最后跳的1次 虽然 和前面满足距离关系  但是可能直接跳到原有石头的下一个上  还是用刚刚的例子解释 13 15 之后是新加18 之后新加 20 之后是原有的22   但是其实是可以从18 直接到20 的 避免这种错误的方式有2种    

一种 是按这种方式先加石头  然后模拟青蛙来跳一次   还有一种是我下面代码用的  最后取模得到的数字减一 最后2次 手动判断一下 然后转换成第一种 距离<=L的来做 更多细节见代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cctype>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<algorithm>
#include<set>
#define scnaf scanf
#define cahr char
#define bug puts("bugbugbug");
using namespace std;
typedef long long ll;
const int mod=1000000007;
const int maxn=2e5+500;
const int inf=1e9+10000;
const int maxe=2e5+100;
int a[maxn];
int main()
{
    int T_T,test=1;
    scnaf("%d",&T_T);
    while(T_T--)
    {
        int n,m,k;
        scnaf("%d%d%d",&n,&m,&k);
        int dis=k;//记录跟上一个点的差值 初始设成k 因为从0开始跳时 第一次应该跳一
        for(int i=0; i<n; i++)
        {
            scanf("%d",&a[i]);
        }
        a[n]=0;
        a[n+1]=m;
        sort(a,a+n+2);
        n+=2;
        int ans=0,now=0,cnt=0;
        for(int i=1; i<n; i++)//去重
            if(a[i]==a[i-1]) {cnt++;a[i]=inf;}
        sort(a,a+n);
        n-=cnt;
        for(int i=1; i<n; i++)
            {
                if(a[i]==a[now]) continue;//因为我更改了a[i]的值 所以还可能有重复
                if(a[i]-a[now]<=k)
                {
                    if(i==n-1||a[i+1]-a[now]>k)
                    {
                        dis=a[i]-a[now];
                        now=i;
                        ans++;
                    }
                }
                else
                {
                    int cha=a[i]-a[now];
                    int num=cha/(k+1)-1;
                    ans+=2*num;
                    a[now]+=num*(k+1);
                    while(a[i]-a[now]>k)
                    {
                        dis=k+1-dis;
                        a[now]+=dis;
                        ans++;
                    }
                    i--;//更改a[now]的位置 转换到第一种情况
                }
            }
        printf("Case #%d: %d\n",test++,ans);
    }


}   

0 0
原创粉丝点击