题目链接:https://ac.nowcoder.com/acm/problem/14844
题意:在数轴上有n个城市,告诉你每个城市的坐标,有一个人在已知的p点,求这个人累计到达m个城市(可以重复)时所走过距离的最小值。注意:这个p点一定不会和任意一个城市重合。
思路:首先要明白,这个人是可以在两个相邻的城市之间左右横跳的(虽然不用灭火但还是要左右横跳),那么选择那两座城市来左右横跳是十分明显的,那就是相距最近的两座城市。但是,很可能存在你还没到那两座城市中的任何一座,结果你就已经到达了m个城市,那么问题就复杂了,于是我们想到了枚举,每次都枚举相邻的两座城市,就假设这个人在这两座城之间横跳,当然如果再走到其中之一时已经经历了m座城市,那就说明这个城市应当放弃,不能到达这里。这样一来,我们就把问题简化了。
但是,如果按着这个思路写,交一发,必WA,这是问什么呢。因为这么做,如果这两座城不是把p点夹在中间的那两座城,就会使得我们完完全全抛弃了某一边的城市,但是事实是有可能到另一边的第一座城在返回来所走的总距离会更小。所以我们每次都要特别判断一下,需不需要退一步再重新向前。至此代码也就可以写出来了。

//author CN.TTDragon
#include<bits/stdc++.h>
typedef long long ll;
const ll mod=1e9+7;
const ll maxn=1e5+7;
const double pi=acos(-1);
using namespace std;
ll a[maxn]={0};
int main()
{
    ll t;
    cin>>t;
    while(t--)
    {
        memset(a,0,sizeof(a));
        ll n,m,p;
        ll ans=1e17;//答案是一个不断取小的过程,开局给个大点的数。
        cin>>n>>m>>p;
        ll weizhi=0;//p点左边的城市。特殊情况下面有补充。
        for(ll i=1;i<=n;i++)
        {
            cin>>a[i];
            if(p>a[i])
            {
                weizhi=i;//确定离p点最近的左边城市,当它为0时,表示所有城市都在它右边 
            }
        }    
        //在i 和 i+1 之间 徘徊
        //如果到达i+1或者i(具体看向左还是向右) 之前 已经经历了m个城市,就continue掉 
        for(ll i=1;i<=n-1;i++)
        {
            if(i<=weizhi)
            {    
                if(weizhi-i+1>m)
                {
                    continue;    //已经走过的城市数量大于了m 
                } 
                ll need=m-(weizhi-i+1);//还需要几次横跳 (不是左右横跳,是 i->i+1 或者 i+1-> i。)
                ll tot=p-a[i];//已经走了的距离
                ans=min(ans,tot+need*(a[i+1]-a[i])); 
                //这里是处理hack数据的,也就是向右一步走,再向左走 
                if(need&&weizhi+1<=n)
                {
                    ans=min(ans,(a[weizhi+1]-p)*2+tot+(need-1)*(a[i+1]-a[i]));
                }
            }
            else
            {
                if(i-weizhi>m) 
                {
                    continue;
                }
                ll need=m-(i-weizhi);
                ll tot=a[i]-p;
                ans=min(ans,tot+need*(a[i+1]-a[i]))    ;
                if(need&&weizhi>=1){
                    ans=min(ans,(p-a[weizhi])*2+tot+(need-1)*(a[i+1]-a[i]));
                }        
            }    
        }
        cout<<ans<<endl;    
    } 
     return 0;
}

写在最后:
这题我只想到要在距离最小的城市之间左右横跳,剩下都是看大佬的才写出来的(其实是照着打的)。
至于他为什么一定会反复横跳可以看 超级大佬的博客 。然后还有一位大佬用 dfs 实现了,真强啊。
最后吐槽一下,邓老师怎么可以直接 ctrl-c + ctrl-v 呢~