ABC353F 分討

ilibilib發表於2024-06-17

回來補補題。

分析:

我先考慮 \(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;
}

相關文章