跳房子(ybtoj-单调队列)
文章目錄
- 題目描述
- 解析
- 代碼
- thanks for reading!
題目描述
洛谷傳送門
跳房子,也叫跳飛機,是一種世界性的兒童游戲,也是中國民間傳統的體育游戲之一。
跳房子的游戲規則如下:
在地面上確定一個起點,然后在起點右側畫 n 個格子,這些格子都在同一條直線上。每個格子內有一個數字(整數),表示到達這個 格子能得到的分數。玩家第一次從起點開始向右跳,跳到起點右側的一個格子內。第二次再從當前位置繼續向右跳,依此類推。規則規定:
玩家每次都必須跳到當前位置右側的一個格子內。玩家可以在任意時刻結束游戲,獲得的分數為曾經到達過的格子中的數字之和。
現在小 R 研發了一款彈跳機器人來參加這個游戲。但是這個機器人有一個非常嚴重的缺陷,它每次向右彈跳的距離只能為固定的 d 。小 R 希望改進他的機器人,如果他花 g 個金幣改進他的機器人,那么他的機器人靈活性就能增加 g ,但是需要注意的是,每 次彈跳的距離至少為 1 。具體而言,當 g<d 時,他的機器人每次可以選擇向右彈跳的距離為 d-g,d-g+1,d-g+2d,…, d+g-2 , d+g-1, d+gd+g ;否則(當 g≥d 時),他的機器人每次可以選擇向右彈跳的距離為 1, 2 , 3 ,…, d+g-2 , d+g-1 , d+g。
現在小 R 希望獲得至少 k 分,請問他至少要花多少金幣來改造他的機器人。
輸入格式
第一行三個正整數 n , d , k ,分別表示格子的數目,改進前機器人彈跳的固定距離,以及希望至少獲得的分數。相鄰兩個數 之間用一個空格隔開。
接下來 n 行,每行兩個整數 xi,si ,分別表示起點到第 i 個格子的距離以及第 ii 個格子的分數。兩個數之間用一個空格隔開。保證 x i按遞增順序輸入。
輸出格式
共一行,一個整數,表示至少要花多少金幣來改造他的機器人。若無論如何他都無法獲得至少 k 分,輸出 ?1 。
解析
其實不算太難
就是一個滑動窗口的題的改版
細節處理的不夠好:
1.二分的上界應該是距離的最大值而不是n!
2.因為s可能很大,所以數組下標不能存具體的s值,而是一個求序號!
代碼
#include <bits/stdc++.h> using namespace std; #define ll long long const int N=550050; int n,d,kk; int pl[N],v[N];ll dp[N];//dp存序號 ll q[N],st,ed,npl; bool check(int k){dp[0]=0;for(int i=1;i<=n;i++) dp[i]=-2e15;st=1,ed=0,npl=0;int l1=d+k,l2=max(1,d-k);for(int i=1;i<=n;i++){while(st<=ed&&pl[q[st]]<pl[i]-l1) st++;while(pl[npl]<=pl[i]-l2&&npl<=n){if(pl[npl]<pl[i]-l1){npl++;continue;}while(st<=ed&&dp[q[ed]]<=dp[npl]) ed--;q[++ed]=npl;npl++;}if(st>ed) dp[i]=-2e15;else dp[i]=dp[q[st]]+v[i];} for(int i=1;i<=n;i++){ // printf("i=%d dp=%d\n",i,dp[i]);if(dp[i]>=kk) return true;}return false; }int main(){scanf("%d%d%d",&n,&d,&kk);for(int i=1;i<=n;i++) scanf("%d%d",&pl[i],&v[i]);check(100);int sst=0,eed=pl[n]+1;while(sst<eed){int mid=(sst+eed)>>1; // printf("**ed=%d\n",ed);if(check(mid)) eed=mid;else sst=mid+1; // printf("mid=%d st=%d ed=%d\n",mid,st,ed);}// printf("st=%d\n",st);if(sst==n+1) printf("-1");else printf("%d",sst); return 0; } /* 50 3 1 49 1 1 26 1 4 6 1 1010 3 1 3 1 1 7 3 2 1 6 5 */thanks for reading!
總結
以上是生活随笔為你收集整理的跳房子(ybtoj-单调队列)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 粉刷木板(ybtoj-单调队列)
- 下一篇: 矩阵快速幂一篇通