NOIP2012 開車旅行 (倍增)

2021-08-10 09:06:02 字數 2994 閱讀 3667

小 a 和小 b 決定利用假期外出旅行,他們將想去的城市從 1 到 n 編號,且編號較小的城市在編號較大的城市的西邊,已知各個城市的海拔高度互不相同,記城市 i 的海拔高度為hi,城市 i 和城市 j 之間的距離 d[i,j]恰好是這兩個城市海拔高度之差的絕對值,即d[i,j] = |hi− hj|。 旅行過程中,小 a 和小 b 輪流開車,第一天小 a 開車,之後每天輪換一次。他們計畫選擇乙個城市 s 作為起點,一直向東行駛,並且最多行駛 x 公里就結束旅行。小 a 和小 b的駕駛風格不同,小 b 總是沿著前進方向選擇乙個最近的城市作為目的地,而小 a 總是沿著前進方向選擇第二近的城市作為目的地(注意:本題中如果當前城市到兩個城市的距離相同,則認為離海拔低的那個城市更近)。如果其中任何一人無法按照自己的原則選擇目的城市,或者到達目的地會使行駛的總距離超出 x 公里,他們就會結束旅行。在啟程之前,小 a 想知道兩個問題:

1.對於乙個給定的 x=x0,從哪乙個城市出發,小 a 開車行駛的路程總數與小 b 行駛的路程總數的比值最小(如果小 b 的行駛路程為 0,此時的比值可視為無窮大,且兩個無窮大視為相等)。如果從多個城市出發,小 a 開車行駛的路程總數與小 b 行駛的路程總數的比值都最小,則輸出海拔最高的那個城市。

2.對任意給定的 x=xi和出發城市 si,小 a 開車行駛的路程總數以及小 b 行駛的路程總數。

先用std::set預處理出對於每乙個位置小a會走到**,小b會走到**;然後考慮倍增,用ne

xai,

j 表示從第

i 個位置開始二人分別走2j

次,小a走的距離之和,ne

xbi,

j 同理,po

si,j

表示從i 開始走2j

次後的位置,直接處理每個詢問即可。

//author: hany01

#include

#define for(i , j , k) for (register int i = (j) , _##end_ = (k) ; i <= _##end_ ; ++ i)

#define fordown(i , j , k) for (register int i = (j) , _##end_ = (k) ; i >= _##end_ ; -- i)

#define set(a , b) memset(a , b , sizeof(a))

#define pb(a) push_back(a)

#define mp(a, b) make_pair(a, b)

#define inf (0x3f3f3f3f)

#define inf1 (2139062143)

#define mod (1000000007)

using

namespace

std;

typedef

long

long ll;

template

inline

bool chkmax(t &a , t b)

template

inline

bool chkmin(t &a , t b)

int _ , __;

char c_;

inline

int read()

inline

void file()

const

int maxn = 100010;

struct item

};set

set;

typedef

set::iterator it;

struct frac

bool

operator == (const frac &a) const

};int n , h[maxn] , s[maxn] , x[maxn] , m , min1 , min2 , nexa[maxn] , nexb[maxn] , pos[maxn][18] , log2n;

ll lena[maxn][18] , lenb[maxn][18];

inline

void checkmin(int &min1 , int &min2 , int id , int now)

inline

void init()

).first , it;

if (itt != set.begin())

}if (itt != -- set.end())

nexb[i] = min1, nexa[i] = min2;

}for(i , 1 , n)

log2n = (int)ceil(log(n * 1.0) / log(2.0));

for(i , 1 , log2n) for(j , 1 , n)

}inline

void solve1()

, tmp;

h[0] = -inf;

for(i , 1 , n)

if (nexa[now] && suma + sumb + lena[now][0] <= x[0]) suma += lena[now][0];

tmp = (frac);

if (!suma && !sumb) continue;

if (!chkmin(ans , tmp) && tmp == ans && h[i] > h[ans.id]) ans = tmp;

}printf("%d\n" , ans.id);

}inline

void solve2()

if (nexa[now] && suma + sumb + lena[now][0] <= x[i]) suma += lena[now][0];

printf("%d %d\n", suma, sumb);

}}int main()

//燕台一去客心驚,笳鼓喧喧漢將營。

//萬里寒光生積雪,三邊曙色動危旌,

//沙場烽火侵胡月,海畔雲山擁薊城。

//少小雖非投筆吏,**還欲請長纓。

//--祖詠《望薊門》

NOIP2012開車旅行 倍增

小 a 和小 b 決定利用假期外出旅行,他們將想去的城市從 1 到 n 編號,且編號較小的城市在編號較大的城市的西邊,已知各個城市的海拔高度互不相同,記城市 i 的海拔高度為hi,城市 i 和城市 j 之間的距離 d i,j 恰好是這兩個城市海拔高度之差的絕對值,即d i,j hi hj 旅行過程中...

noip2012 開車旅行 set 倍增

因為要快速查詢向後跳應該是哪乙個點,所以用set,迭代器左右晃一下查詢最接近的兩個元素 p選手是不是只能用平衡樹 然後用倍增記錄i節點跳2 j步後,a和b分別走的距離。具體的細節和統計答案也需要注意。include include include include include include de...

NOIP2012 開車旅行 SET 倍增

啊,看到題 字好多。然後就直接開始碼暴力模擬了,覺得可以預處理一下每個點可以到達的最近點和次近點,這樣大概就有50分了 然而實際有70分。我忽略了只能往後走這一點帶來的便利,於是每一次都要找一次最近點 次近點 果然弱啊 暴力的過程寫的蠻。第一次只騙到15分 後來發現了bug調到35.就開始在精度這裡...