【CodeForces - 1041D】Glider (枚举起点,双指针 或 二分终点,思维)(知识点总结)
題干:
A plane is flying at a constant height of?hh?meters above the ground surface. Let's consider that it is flying from the point?(?109,h)(?109,h)?to the point?(109,h)(109,h)?parallel with?OxOx?axis.
A glider is inside the plane, ready to start his flight at any moment (for the sake of simplicity let's consider that he may start only when the plane's coordinates are integers). After jumping from the plane, he will fly in the same direction as the plane, parallel to?OxOx?axis, covering a unit of distance every second. Naturally, he will also descend; thus his second coordinate will decrease by one unit every second.
There are ascending air flows on certain segments, each such segment is characterized by two numbers?x1x1?and?x2x2?(x1<x2x1<x2) representing its endpoints. No two segments share any common points. When the glider is inside one of such segments, he doesn't descend, so his second coordinate stays the same each second. The glider still flies along?OxOx?axis, covering one unit of distance every second.
?If the glider jumps out at?11, he will stop at?1010. Otherwise, if he jumps out at?22, he will stop at?1212.
Determine the maximum distance along?OxOx?axis from the point where the glider's flight starts to the point where his flight ends if the glider can choose any integer coordinate to jump from the plane and start his flight. After touching the ground the glider stops altogether, so he cannot glide through an ascending airflow segment if his second coordinate is?00.
Input
The first line contains two integers?nn?and?hh?(1≤n≤2?105,1≤h≤109)(1≤n≤2?105,1≤h≤109)?— the number of ascending air flow segments and the altitude at which the plane is flying, respectively.
Each of the next?nn?lines contains two integers?xi1xi1?and?xi2xi2?(1≤xi1<xi2≤109)(1≤xi1<xi2≤109)?— the endpoints of the?ii-th ascending air flow segment. No two segments intersect, and they are given in ascending order.
Output
Print one integer?— the maximum distance along?OxOx?axis that the glider can fly from the point where he jumps off the plane to the point where he lands if he can start his flight at any integer coordinate.
Examples
Input
3 4 2 5 7 9 10 11Output
10Input
5 10 5 7 11 12 16 20 25 26 30 33Output
18Input
1 1000000000 1 1000000000Output
1999999999Note
In the first example if the glider can jump out at?(2,4)(2,4), then the landing point is?(12,0)(12,0), so the distance is?12?2=1012?2=10.
In the second example the glider can fly from?(16,10)(16,10)?to?(34,0)(34,0), and the distance is?34?16=1834?16=18.
In the third example the glider can fly from?(?100,1000000000)(?100,1000000000)?to?(1999999899,0)(1999999899,0), so the distance is?1999999899?(?100)=19999999991999999899?(?100)=1999999999.
題目大意:
? 你現在處于高度為h的地方,每秒y坐標會減少1,x坐標會增加1,而現在會有n個氣流區[l,r],在每個氣流區中,你的y坐標不會改變,你的x坐標每秒會增加1。(保證所給出的氣流兩兩之間沒有交集)現在你可以從x軸上的任意一點下落,現在問你最遠的飛行路徑。(即終點x坐標 減 起點x坐標的最大值)
解題報告:
? ?大體:看到數據量,nlogn解決,于是乎枚舉每一個起點,二分找到終點,維護最大值,就可以了呀。
仔細分析:
首先要分析出,把豎直下落的高度轉換成走過的間隙的長度和(高中物理題貌似這種轉化套路很多見?)然后我們看在這些個間隙下,能走多長個氣流(不是越多越好,而是越長越好),維護一個maxx,然后最后答案就是maxx + h就可以了。
不明白可以看下面的圖:
可以看成是這個東西:
相當于是在選取的ci≤h的情況下,使Σwi最大。
AC代碼:
#include<bits/stdc++.h>using namespace std; const int MAX = 2e5 + 5; int n,h; int b[MAX],c[MAX]; struct Node {int l,r; } node[MAX]; int main() {cin>>n>>h;for(int i = 1; i<=n; i++) scanf("%d%d",&node[i].l,&node[i].r);c[1] = 0;b[1] = node[1].r-node[1].l;for(int i = 2; i<=n; i++) {b[i] = node[i].r - node[i].l;c[i] = node[i].l - node[i-1].r;b[i] += b[i-1];c[i] += c[i-1];}c[n+1] = INT_MAX;//這句貌似可以沒有、、int maxx = -1,ans;for(int i = 1; i<=n; i++) {int pos = lower_bound(c+1,c+n+1,c[i]+h) - c;ans = b[pos-1] - b[i-1];maxx = max(maxx,ans);}printf("%d\n",maxx+h);return 0 ; } /* 2 3 1 2 3 4 */總結:
? ?就是要多逼著自己做做D題啊!!!有的時候也不算很難想,不是高不可攀,是不是?
關于初始化:這里對于i=1的情況單獨做了初始化,然后從i=2開始進入for循環,是正解,但是不加初始化,直接i=1開始計入for,也可以ac,但是就說不太過去,反正輸出c[2]的值是和我們想得到的值是不一樣的,換句話說,是不合法的。
記住一個套路:
? ? ?求前綴和 + 二分。其中二分尋值時可以依附于正在枚舉的i上,就像這個題,二分找的就是c[i]相關的。這樣就避免了很麻煩的雙指針:鏈接在此
#include <bits/stdc++.h> #define maxn 200005 using namespace std; struct Node{int l,r; }q[maxn]; typedef long long ll; int main() {ll n,h;cin>>n>>h;for(int i=0;i<n;i++){scanf("%I64d%I64d",&q[i].l,&q[i].r);}ll l,r,tmp1,tmp2;l=q[0].l,r=q[0].r+h;//首先l指針先指向第一個氣流的起點,r指針指向落點ll ans=h;tmp1=tmp2=0;while(tmp1<n){//枚舉每一個氣流while(tmp2+1<n&&q[tmp2+1].l<r){//如果下一個氣流的左區間在終點前,則證明出現情況2,則將終點加上該氣流的區間大小tmp2++;r+=q[tmp2].r-q[tmp2].l;}ans=max(ans,r-l);//記錄r-l的最大值tmp1++;l=q[tmp1].l;//將起點置為下一個氣流的起點r+=q[tmp1].l-q[tmp1-1].r; //加上氣流與氣流之間的大小}cout<<ans<<endl; }或者一位紅名大佬的雙指針:
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int, int> pii; #define mp make_pair const int N = 200200; int n, h; int a[N][2]; int ans; int main() {scanf("%d%d", &n, &h);for (int i = 0; i < n; i++) scanf("%d%d", &a[i][0], &a[i][1]);int r = 0;int curH = h;for (int l = 0; l < n; l++) {while(r < n - 1 && curH > a[r + 1][0] - a[r][1]) {curH -= a[r + 1][0] - a[r][1];r++;}ans = max(ans, a[r][1] - a[l][0] + curH);if (l < n - 1)curH += a[l + 1][0] - a[l][1];}printf("%d\n", ans);return 0; }或者app大佬:
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 200000; int n, h, l[maxn + 10], r[maxn + 10], m; pair<ll, ll> a[maxn + 10]; int idl = 1, idr = 1; ll lenl = -1e18, lenr = -1e18, ans; int main() {scanf("%d%d", &n, &h);lenr += h; ans = h;for (int i = 1; i <= n; ++i) scanf("%d%d", &l[i], &r[i]);a[++m] = make_pair(-(long long)1e18, l[1]);for (int i = 2; i <= n; ++i)a[++m] = make_pair(r[i - 1], l[i]);a[++m] = make_pair(r[n], (long long)1e18);while (idl <= m && idr <= m) {ans = max(ans, lenr - lenl);ll dist = min(a[idr].second - lenr, a[idl].second - lenl);lenl += dist; lenr += dist;if (lenl < a[idl].second) ++lenl;else lenl = a[++idl].first + 1;if (lenr < a[idr].second) ++lenr;else lenr = a[++idr].first + 1;}printf("%lld", ans); }?
總結
以上是生活随笔為你收集整理的【CodeForces - 1041D】Glider (枚举起点,双指针 或 二分终点,思维)(知识点总结)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: sixtypopsix.exe - si
- 下一篇: 【HDU -1568】 Fibonacc