P1081 開車旅行 倍增 (毒瘤題)

2022-04-30 21:24:16 字數 2621 閱讀 2729

其實就是個大模擬。

首先,根據題意,小a和小b從任意乙個城市開始走,無論\(x\)如何,其路徑是一定唯一的。

顯然對於兩問都可以想出乙個\(o(n^2)\)的暴力,即直接一步一步地向右走。

首先,我們當然需要知道a,b在每個城市的下一步如何走,記\(nexta(i),nextb(i)\)為a,b在\(i\)處時,下一步走到的城市編號。

考慮如何高效(複雜度小於等於\(o(nlogn)\))維護兩個\(next\)。

顯然不能直接維護每個城市與其後面的城市的差值,再好的資料結構也會到\(o(n^2)\)。

不妨考慮從後往前依次插入\(h_i\),然後動態維護\(h_i\sim h_n\)的有序集合。這樣的話,在有序集合中,最小的差值一定要麼是\(h_i\)與其前驅,要麼就是與其後繼的差值。次小的差值,就是\(h_i\)前驅、前驅的前驅、後繼、後繼的後繼與\(h_i\)的差值的次小值。這個問題,平衡樹解決之,預處理\(o(nlogn)\)。

下面考慮走\(k\)步的情況,當前步是a走還是b走與步數的奇偶性有關,因此我們還要分開討論。

那麼,我們不妨考慮以此為基礎進行優化,比如優化到\(o(nlogn)\)。顯然地,對於這樣的問題,我們可以倍增預處理,\(o(logn)\)詢問。

接下來考察我們需要什麼資訊,分別是\(i\)向後走\(k\)步的城市,a和b從\(i\)向後走\(k\)步的路程。

設\(f[0/1][i][j]\)為從\(i\)位置,0a,1b向後走\(2^j\)步的城市。

顯然\[f[0][i][0]=nexta(i)\\f[1][i][0]=nextb(i)

\]由於,走\(2^0\)步是走奇數步,有轉移

\[f[0][i][1]=f[1][f[0][i][0]][0]\\f[1][i][1]=f[0][f[1][i][0]][0]

\]對於走\(2^j\)步,有

\[f[0][i][j]=f[0][f[0][i][j-1]][j-1]\\f[1][i][j]=f[1][f[1][i][j-1]][j-1]

\]設\(da[0/1][i][j]\)表示從\(i\)位置,a向後走\(2^j\)步的路程,且現在(當前步)是0a,1b在開車,還沒走時的a開的距離

顯然\[da[0][i][0]=dist(i,nexta(i))\\da[1][i][0]=0

\]有轉移

\[da[0][i][1]=da[0][i][0]+da[1][f[0][i][0]][0]\\da[1][i][1]=da[1][i][0]+da[0][f[1][i][0]][0]\\da[0][i][j]=da[0][i][j-1]+da[0][f[0][i][j-1]][j-1]\\da[1][i][j]=da[1][i][j-1]+da[1][f[1][i][j-1]][j-1]

\]設\(db[0/1][i][j]\)表示從\(i\)位置,b向後走\(2^j\)步的路程,且現在是0a,1b在開車。

跟\(da\)差別不大,不再贅述。

預處理完成之後,我們開始考慮題述問題。

對於第一問,對給出的\(x_0\),我們列舉城市\(s_i\),倍增統計走\(x_0\)步的答案(當然超出\(n\)要特判),\(o(nlogn)\)解決之。

對於第二問,同樣的,對於每一組\(s_i,x_i\),直接倍增統計即可,複雜度\(o(mlogn)\)。

總複雜度在\(o((n+m)logn)\)左右,完全可以通過本題。

注意,這道題的細節之數量足以讓人去世。

**未經重構,很醜。

#include#include#include#include#include#include#include#include#include#include#include#define inf 0x7fffffff

#define pi acos(-1.0)

#define n 100010

#define mod 2520

#define e 1e-12

#define ll long long

using namespace std;

inline ll read()

while(c>='0'&&c<='9')

return x*f;

}seth;

mapmp;

int t;

ll n,a[n],na[n],nb[n],f[2][n][21],da[2][n][21],db[2][n][21];

int main()

else

f[0][i][0]=na[i];f[1][i][0]=nb[i];

da[0][i][0]=abs(a[i]-a[na[i]]);

db[1][i][0]=abs(a[i]-a[nb[i]]);

} for(int j=1;j<=t;++j)else

} }/

int x0=read(),s0=0;

double ans=1e14,nans=1e14;//task 1

for(int i=1;i<=n;++i)

} nans=(double)resa/(double)resb;

if(nans=0;--j)

} printf("%lld %lld\n",resa,resb);

} return 0;

}

P1081 開車旅行

p1081 開車旅行 排序優化 倍增 其實這道題一開始是一點也沒有頭緒,知道有高人指點了一下。說並不需要拘束於出發點和路徑長度,也就是問題1.2。不過乙個是固定路徑長度的詢問,另乙個是給定起點和路徑長度的詢問。所以問題一和問題二是可以使用乙個函式解決的,而且對於乙個城市來說,在不考慮路程的情況下,路...

P1081 開車旅行

傳送門 用倍增的思想 設 a i 表示a在 i 位置走一步到達的城市以及經過的路程 這裡我用結構體存a i b同理 設 f i j 表示從 i 位置出發,走 2 j 輪後到達的城市 一輪即ab各走一次 dis i j 表示從 i 位置出發,走 2 j 輪後經過總路程 da i j 表示從 i 位置出...

洛谷P1081 開車旅行 (Treap 倍增)

題目傳送門 題目分析 這題的兩個問其實是差不多的。第一問給出了x0,我們列舉起點s,就相當於變成了n個第二類詢問 s x0 1 s n 於是現在原問題變成了 給出 s,x 如何快速求s開始往下走不超過x距離時,a,b各走的距離?然後用資料結構預處理出a,b到達每乙個點之後會走哪個點,詢問時倍增往後跳...