洛谷 P7885 「MCOI-06」Flight題解
這是一道隱藏的很深的結論題好像只是因為我太弱,我一開始看時以為是個模擬,然後看到資料範圍之後我傻了。
怎麼辦呢?我們要堅信暴力出奇跡,打表出省一畫圖可以解決一切問題。
於是這個圖就出來了
然後根據玄學手推可以推出最短路是這個樣子的
由此我們可以得到一種情況,也就是當a=b且c=d時兩點間的最短路為兩點的曼哈頓距離,公式為$|x_1-x_2|+|y_1-y_2|$。敲黑板!曼哈頓距離是本題解題的關鍵
但是毒瘤大犇出題人怎麼可能這麼輕易地就放過我們呢。
於是我們可以通過第一種情況延伸出剩下兩種情況
abcd形成一個長方形的
a=c的(Subtask2)
這裡就會有人問了,誒誒你不是說從第一個延伸出來的嗎,怎麼看著跟第一個一點關係都沒有呢?不要著急,等我把這兩種情況的最短路畫出來你就知道了
第二種情況
第三種情況
我們可以把第二種情況看做先把cd所在的那一行當成正方形的底,然後走一遍情況一,再直走走到點cd
直走我們用的方法是這個樣子的,因為題目要求不能連續往同一個方向走,而這樣走可以被證明每一步是最短的
按這樣直走,我們可以算出直走所需要的的步數,但是這裡需要分類討論(此處為本題巨坑,本蒟蒻卡在這裡調了兩個多小時),一種是兩點的距離為偶數,一種是兩點的距離是奇數。
兩點的距離是偶數時,步數為兩點的距離乘以二,因為每走一步之後需要重置方向,要往上或往下再走一步。
兩點的距離是奇數時,步數為兩點的距離乘以二減一,因為走最後一步時不需要再重置方向了,所以要減去多的一步(斜線劃分步數)
因為當我們從點ab走到正方形的右下角時,正方形的右下角和點cd在一條橫軸上,所以我們直接走直線即可到達點cd,所需的步數即為從點ab走到正方形右下角的步數加從正方形右下角走直線到點cd的步數。
而情況三則比較簡單,直接從點ab走直線到點cd即可。
本題最大的難點在於分類討論和三種情況的解決,都解決後其實就是一道結論題
AC程式碼
#include<iostream> #include<cstdio> #include<cmath> #define int long long//反正空間夠,不開long long見祖宗,而且你必須開 using namespace std; signed main()//因為define了int,所以要改成signed { int T; cin>>T; for(int cishu=0;cishu<T;++cishu){ int a,b,c,d; cin>>a>>b>>c>>d; int ac=abs(a-c),bd=abs(b-d); int temp=ac,ans=min(ac,bd); //哪邊小把哪邊當做正方形的底,要不然就把點cd越過去了 ac-=min(temp,bd);//求需要直走的長度 bd-=min(temp,bd); int bigger=max(ac,bd); if(bigger&1) cout<<(ans*2+bigger*2-1); //位運算判斷奇偶更快 else cout<<(ans*2+bigger*2); cout<<endl; } return 0; }