回來補補題。
分析:
我先考慮 \(k\) 很大的時候,大塊和大塊間的移動,我們不得不盡量避免小塊:
我們容易發現這樣時是最優的,可以發現就是在斜著走,也就是典型的切比雪夫距離。斜著走一次需要經過兩條邊,所以花費是兩倍的切比雪夫距離。
要是起點和終點不在大塊上呢?
首先考慮它們不在同一大塊(這裡的大塊意義不同於前面說的大塊,具體見下)內:
顯然,路徑上必然是從起點到一個相鄰的大塊,然後進行大塊和大塊間的移動到達與終點相鄰的大塊,然後再直直進入。
路徑簡化為:起點 到 起點相鄰的大塊 再到 終點相鄰的大塊 最後到 終點。
我們明確起點和終點,但起點相鄰的大塊和終點相鄰的大塊並不確定,但相鄰的大塊只有 \(4\) 個,所以列舉一下 \(4\times 4\) 就行了,如果起點或終點本來就在大塊上就不用考慮了。
要是它們是在同一大塊的小塊呢?
如圖:
那麼它們間的路徑可能就不會經過大塊了,可以在小塊內之間相互抵達,但也可能經過大塊,所以還是要進行上面的那種討論。
\(k\) 較小時呢?
\(k=1\),顯然就不用考慮那麼多了,直接就是曼哈頓距離了。
\(k=2\) 呢?
大塊間移動的最短距離不再是切比雪夫距離了,特判一下就行了。
\(k=3\) 時就等同於前面 \(k\) 很大的情況啦。
然後我們就可以輕鬆切了這題啦。
code:
#include<bits/stdc++.h>
#define int long long
using namespace std;
int k;
int solve(int x1,int y1,int x2,int y2)
{
if(k==2) return 2*max(abs(x1-x2),abs(y1-y2))-abs(abs(x1-x2)-abs(y1-y2))/2;
return 2*max(abs(x1-x2),abs(y1-y2));
}
vector<pair<pair<int,int>,int>>v[2];
void check(int x,int y,int op)
{
if((x/k+y/k)%2) v[op].push_back({{x/k,y/k},0});
else
v[op].push_back({{x/k-1,y/k},(x%k)+1}),v[op].push_back({{x/k,y/k-1},(y%k)+1}),
v[op].push_back({{x/k+1,y/k},k-(x%k)}),v[op].push_back({{x/k,y/k+1},k-(y%k)});
}
signed main()
{
int x1,y1,x2,y2,ans=1e18;
cin>>k;
cin>>x1>>y1>>x2>>y2;
if(k==1) {cout<<abs(y1-y2)+abs(x1-x2);return 0;}
if(x1/k==x2/k&&y1/k==y2/k) ans=abs(y1-y2)+abs(x1-x2);
check(x1,y1,0);check(x2,y2,1);
for(auto i:v[0]) for(auto j:v[1]) ans=min(ans,solve(i.first.first,i.first.second,j.first.first,j.first.second)+i.second+j.second);
cout<<ans;
return 0;
}