6463: Tak and Hotels II(倍增)
題目描述
N hotels are located on a straight line. The coordinate of the i-th hotel (1≤i≤N) is xi.
Tak the traveler has the following two personal principles:
He never travels a distance of more than L in a single day.
He never sleeps in the open. That is, he must stay at a hotel at the end of a day.
You are given Q queries. The j-th (1≤j≤Q) query is described by two distinct integers aj and bj. For each query, find the minimum number of days that Tak needs to travel from the aj-th hotel to the bj-th hotel following his principles. It is guaranteed that he can always travel from the aj-th hotel to the bj-th hotel, in any given input.
Constraints
2≤N≤105
1≤L≤109
1≤Q≤105
1≤xi<x2<…<xN≤109
xi+1?xi≤L
1≤aj,bj≤N
aj≠bj
N,L,Q,xi,aj,bj are integers.
Partial Score
200 points will be awarded for passing the test set satisfying N≤103 and Q≤103.
輸入
The input is given from Standard Input in the following format:
N
x1 x2 … xN
L
Q
a1 b1
a2 b2
:
aQ bQ
輸出
Print Q lines. The j-th line (1≤j≤Q) should contain the minimum number of days that Tak needs to travel from the aj-th hotel to the bj-th hotel.
樣例輸入
樣例輸出
4 2 1 2提示
For the 1-st query, he can travel from the 1-st hotel to the 8-th hotel in 4 days, as follows:
Day 1: Travel from the 1-st hotel to the 2-nd hotel. The distance traveled is 2.
Day 2: Travel from the 2-nd hotel to the 4-th hotel. The distance traveled is 10.
Day 3: Travel from the 4-th hotel to the 7-th hotel. The distance traveled is 6.
Day 4: Travel from the 7-th hotel to the 8-th hotel. The distance traveled is 10.
題意:給你直線上一些點的坐標,一天最大的移動距離,要求每天結束時必須在一個點上。1e5次詢問,每次詢問從第a個點到第b個點最少要幾天。
解題思路:
dp[x][y]表示第x個點2^y次方的天數能到的最遠點。暴力或二分預處理dp[x][0],然后 dp[x][i] = dp[f[x][i-1]][i-1];
查詢的時候, 找到從cur(當前點)出發的第一個小于b位置的dp[cur][j],最后答案加上1(2^0)
//dp[x][y]表示第x個點2^ y次方的天數能到的最遠點。
dp[j][i]=dp[dp[j][i?1]][i?1];dp[j][i] = dp[dp[j][i - 1]][i - 1];dp[j][i]=dp[dp[j][i?1]][i?1];
// 含義以i等于1為例,意義是第j個點2天能到的最遠點。那么這不就是我一天最遠能走到的點,的一天能走到的最遠的點嘛
//其余的就可以依次類推
代碼:
int main() {while (cin >>n) {for (int i = 1; i <= n; ++i)cin >> a[i];cin >> L >> Q;for (int i = 1; i <= n; ++i) {//upper_bound()是找到第一個大于的位置,-a得到下標,再減1得到最后一個小于等于的點int id = upper_bound(a + 1, a + 1 + n, a[i] + L)-a-1;if (a[i] + L >= a[n]) //如果可以一次過那么在一天內就可以直接到n點了dp[i][0] = n;elsedp[i][0] = id;}for (int i = 1; i <= 30; ++i)for (int j = 1; j <= n; ++j)dp[j][i] = dp[dp[j][i - 1]][i - 1];while (Q--) {cin >> x >> y;if (x > y) swap(x, y);ans = 0;//從大到小枚舉for (int i = 30; i >= 0; --i) {if (dp[x][i] < y) //從第一個點走的2^i的天數如果小于y,那么這個天數對于x點最優{ans += (1) << i;x = dp[x][i]; //如果還沒到終點以這個點來找} }cout << ans+1 << endl;} }return 0; }lower_bound( )和upper_bound( )都是利用二分查找的方法在一個排好序的數組中進行查找的。
在從小到大的排序數組中,
lower_bound( begin,end,num):從數組的begin位置到end-1位置二分查找第一個大于或等于num的數字,找到返回該數字的地址,不存在則返回end。通過返回的地址減去起始地址begin,得到找到數字在數組中的下標。
upper_bound( begin,end,num):從數組的begin位置到end-1位置二分查找第一個大于num的數字,找到返回該數字的地址,不存在則返回end。通過返回的地址減去起始地址begin,得到找到數字在數組中的下標。
總結
以上是生活随笔為你收集整理的6463: Tak and Hotels II(倍增)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ARC-060C - Tak and C
- 下一篇: 实数问题