[ABC353F] Tile Distance 題解

louisliang發表於2024-05-18

[ABC353F] Tile Distance 題解

題目傳送門:洛谷, Atcoder

Solution

很噁心人的分類討論題。

很顯然走大格子大機率比走小格子快。

對終點和起點向上下左右列舉大格子,我們就把問題轉化為給兩個大格子 \((a,b)\)\((c,d)\),求怎樣走最快。

對角的大格子可以透過 \(2\) 步相互到達,如下圖所示。

於是我們可以以以下路徑,這是一般情況的最短路徑,步數為 \(max(|a-c|,|b-d|)\)。(據說這是切比雪夫距離)

然而當 \(k \leq 2\),最後一段路不需要上下橫跳,直接橫穿小格子即可,步數為 \(\frac{k+1}{2}min(|a-c|,|b-d|)+||a-c|-|b-d||\)

最後要討論只透過小格子達到的情況,就讓上面算出的答案和曼哈頓距離去最小值就好了。

注意:若起點和終點在同一個小格子的塊中,答案不一定是他們的曼哈頓距離,就像下圖所示的情況,顯然紅線比綠線短。

code

#include<iostream>
#include<vector>
#include<algorithm>
#include<string>
#include<queue>
#include<cstring>
#include<cmath>
#include<cassert>
#define pr pair < long long, pair<long long, long long> >
#define mp make_pair
using namespace std;
long long k, sx, sy, tx, ty;
long long gt(long long ax, long long ay, long long bx, long long by){
	long long a = abs(ax - bx), b = abs(ay - by), ans = max(a, b) * 2, sp = max(a, b) - min(a, b);
	if(k == 1)
		return a + b;
	if(k == 2)
		return a + b + sp / 2;
	return ans;
}
vector < pr > a, b;
int main(){
	cin >> k >> sx >> sy >> tx >> ty;
	long long dsx = sx / k, dsy = sy / k, dtx = tx / k, dty = ty / k;
	long long dis = max(sx, tx) - min(sx, tx) + max(sy, ty) - min(sy, ty);
	if((dsx + dsy) % 2 == 0){
		a.push_back(mp(sx - dsx * k + 1, mp(dsx - 1, dsy)));
		a.push_back(mp(sy - dsy * k + 1, mp(dsx, dsy - 1)));
		a.push_back(mp((dsx + 1) * k - sx, mp(dsx + 1, dsy)));
		a.push_back(mp((dsy + 1) * k - sy, mp(dsx, dsy + 1)));
	}
	else
		a.push_back(mp(0, mp(dsx, dsy)));
	if((dtx + dty) % 2 == 0){
		b.push_back(mp(tx - dtx * k + 1, mp(dtx - 1, dty)));
		b.push_back(mp(ty - dty * k + 1, mp(dtx, dty - 1)));
		b.push_back(mp((dtx + 1) * k - tx, mp(dtx + 1, dty)));
		b.push_back(mp((dty + 1) * k - ty, mp(dtx, dty + 1)));
	}
	else
		b.push_back(mp(0, mp(dtx, dty)));
	long long minn = dis;
	for(auto i : a)
		for(auto j : b)
			minn = min(minn, i.first + j.first + gt(i.second.first, i.second.second, j.second.first, j.second.second));
	cout << minn << endl;
	return 0;
}

相關文章