版權yangyaojia.cnblogs.com
noip2012 day1 t3
題目大意
給出n個排成一行的城市,每個城市有乙個不同的海拔。定義兩個城市間的距離等於他們的高度差的絕對值,且絕對值相等的時候海拔低的距離近。有兩個人輪流開車,從左往右走。a每次都選最近的,b每次都選次近的。旅行時有乙個總路程x,如果兩個人的總路程》x 或 有乙個人無法按照自己的原則選擇目的城市,旅行就終止。
1.給出x0,求從哪乙個城市出發,使得a走的路程/b走的路程最小。如果b走的路程=0,則比值視為無窮大。如果有多個城市滿足要求,則輸出海拔最高的那個城市。
2.給出x和s(出發城市),求旅行終止是a的路程和b的路程。
輸入描述 input description
第一行包含乙個整數 n,表示城市的數目。
第二行有 n 個整數,每兩個整數之間用乙個空格隔開,依次表示城市 1 到城市 n 的海拔高度,即h1,h2,……,hn,且每個hi都是不同的。
第三行包含乙個整數 x0。
第四行為乙個整數 m,表示給定m組si和 xi。
接下來的m行,每行包含2個整數si和xi,表示從城市 si出發,最多行駛xi公里。
輸出描述 output description
輸出共m+1 行。
第一行包含乙個整數s0,表示對於給定的x0,從編號為s0的城市出發,小a開車行駛的路程總數與小b行駛的路程總數的比值最小。
接下來的 m 行,每行包含 2 個整數,之間用乙個空格隔開,依次表示在給定的 si和xi下小a行駛的里程總數和小b 行駛的里程總數。
樣例輸入
4輸出12 3 1 4
3 4
1 3
2 3
3 3
4 3
1 12 0
0 00 0
【資料範圍】
對於 30%的資料,有 1≤n≤20,1≤m≤20;
對於 40%的資料,有 1≤n≤100,1≤m≤100;
對於 50%的資料,有 1≤n≤100,1≤m≤1,000;
對於 70%的資料,有 1≤n≤1,000,1≤m≤10,000;
對於100%的資料,有1≤n≤100,000,1≤m≤10,000,-1,000,000,000≤hi≤1,000,000,000,
0≤x0≤1,000,000,000,1≤si≤n,0≤xi≤1,000,000,000,資料保證 hi互不相同。
解題方案
這一道題翻了題解才做出來,我在這裡總結一下。
我們很容易可以發現,這可以用線段上的倍增來跳點。
我們可以把a和b合成一輪,這樣我們用f[i][j]帶表從第i個點跳2j輪所到達的點。
用da[i][j]代表第i個點跳2j輪所到達的點時a所走的路程。db[i][j]也是同樣的意義。
所以計算路程的方法與倍增跳點的方法一樣。關鍵是怎麼出預處理,求出da[i][0],db[i][0],與f[i][0]
其實,網上有很多介紹預處理的實現方法,但主要的思想都是這樣的:
我們可以從n到1依次將點(以其高度為關鍵字,並記下其編號)丟入乙個有序佇列。那麼如果剛加進的點序號為i,最近點與次近點只可能在i-2,i-1,i+1,i+2中。我們就可以在這裡確定陣列sa[i],代表i號點的次近點,sb[i]代表i號點最近點。因為加入的順序為n到1,所以肯定是合理的。
我們可以得到
f[i][0]=sb[sa[i]];
da[i][0]=abs(h[i]-h[sa[i]]);
db[i][0]=abs(h[sa[i]]-h[sb[sa[i]]]);
具體怎麼實現,好像可以用離散化+鍊錶,雙向鍊錶,平衡樹.....但我認為最6的還是 stl 的 set
預處理好了,我們就可以按照倍增的方法,求出再限定距離能跳的點。注意,會有情況b跳不了單a跳的了,我們要特殊處理。
對於第一問,可以列舉。o(n log n)
第二問 就是詢問 o(log n)
要開long long!
#include #include#include
#include
#include
#include
#include
#include
#define maxn 100000+10
#define pair pairusing
namespace
std;
long
long
n,a[maxn],sa[maxn],sb[maxn],x0,m;
long
long f[maxn][20],da[maxn][20],db[maxn][20
];long
long
read()
sets;
set:: iterator it1;
set:: iterator it2;
void
init()
}if(it2!=--s.end())
}sort(tmp+1,tmp+num+1
); sb[i]=tmp[1
].second;
if(num>=2) sa[i]=tmp[2
].second;
f[i][
0]=sb[sa[i]];
if(sa[i]) da[i][0]=abs(a[i]-a[sa[i]]);
if(sb[sa[i]]&&sa[i]) db[i][0]=abs(a[sa[i]]-a[sb[sa[i]]]);
}for(long
long j=1;(1
}}long
long query(long
long x,long
long d,long
long &xx,long
long &yy)
if(sa[a]&&ansa+ansb+da[a][0]<=d)
ansa+=da[a][0
]; xx=ansa;
yy=ansb;
}int
main()}}
printf(
"%lld\n
",bp);
scanf(
"%lld
",&m);
for(long
long i=1;i<=m;i++)
//*/
return0;
}
NOIp2012 開車旅行
傳送門 以後序列上的問題可以想一想倍增。s a i s b i sa i sb i sa i sb i 記錄在i ii這個位置讓a b a ba b開車到達的點。把a aa和b bb都跳一次稱為一輪。d is i j dis i j dis i j 表示從i ii跳2 j2 j 2j輪的總路程。p ...
Noip2012 開車旅行
小 a 和小 b 決定利用假期外出旅行,他們將想去的城市從 1 到 n 編號,且編號較小的城市在編號較大的城市的西邊,已知各個城市的海拔高度互不相同,記城市 i 的海拔高度為hi,城市 i 和城市 j 之間的距離 d i,j 恰好是這兩個城市海拔高度之差的絕對值,即d i,j hi hj 旅行過程中...
NOIP2012 開車旅行
題目描述 小 a 和小 b 決定利用假期外出旅行,他們將想去的城市從 1 到 n 編號,且編號較小的 城市在編號較大的城市的西邊,已知各個城市的海拔高度互不相同,記城市 i 的海拔高度為 hi,城市 i 和城市 j 之間的距離 d i,j 恰好是這兩個城市海拔高度之差的絕對值,即 d i,j hi ...