zoukankan      html  css  js  c++  java
  • 【单调队列】【P3957】 跳房子

    传送门

    Description

    跳房子,也叫跳飞机,是一种世界性的儿童游戏,也是中国民间传统的体育游戏之一。

    跳房子的游戏规则如下:

    在地面上确定一个起点,然后在起点右侧画 $n$ 个格子,这些格子都在同一条直线上。每个格子内有一个数字(整数),表示到达这个 格子能得到的分数。玩家第一次从起点开始向右跳,跳到起点右侧的一个格子内。第二次再从当前位置继续向右跳,依此类推。规则规定:

    玩家每次都必须跳到当前位置右侧的一个格子内。玩家可以在任意时刻结束游戏,获得的分数为曾经到达过的格子中的数字之和。

    现在小 $R$ 研发了一款弹跳机器人来参加这个游戏。但是这个机器人有一个非常严重的缺陷,它每次向右弹跳的距离只能为固定的 $d$ 。小 $R$ 希望改进他的机器人,如果他花 $g$ 个金币改进他的机器人,那么他的机器人灵活性就能增加 $g$ ,但是需要注意的是,每 次弹跳的距离至少为 $1$ 。具体而言,当 $g<d$ 时,他的机器人每次可以选择向右弹跳的距离为 $d-g,d-g+1,d-g+2$ ,…, $d+g-2$ , $d+g-1$ , $d+g$ ;否则(当 $g geq d$ 时),他的机器人每次可以选择向右弹跳的距离为 $1$ , $2$ , $3$ ,…, $d+g-2$ , $d+g-1$ , $d+g$ 。

    现在小 $R$ 希望获得至少 $k$ 分,请问他至少要花多少金币来改造他的机器人。

    Input

    第一行三个正整数 $n$ , $d$ , $k$ ,分别表示格子的数目,改进前机器人弹跳的固定距离,以及希望至少获得的分数。相邻两个数 之间用一个空格隔开。

    接下来 $n$ 行,每行两个正整数 $x_i,s_i$ ,分别表示起点到第 $i$ 个格子的距离以及第 $i$ 个格子的分数。两个数之间用一个空格隔开。保证 $x_i$ 按递增顺序输入。

    Output

    共一行,一个整数,表示至少要花多少金币来改造他的机器人。若无论如何他都无法获得至少 $k$ 分,输出 $-1$ 。

    Hint

    (For~all:)

    (1~leq~n~leq~500000~,~1~leq~d~leq~2000~,~1~leq~x_i,k~leq~10^9~,~|s_i|~leq~10^5)

    Solution

    这显然是个满足单调性的问题,于是考虑二分解决。

    二分一个答案(x),那么即求出花费(x)的金币以后能得到的最大分数。考虑DP一波。

    (f_i)为跳到第(i)个格子的答案。从前面枚举上一个位置转移,时间复杂度(O(n^2logn)),期望得分(50pts)

    考虑每一个(i)的转移都是从同样长的区间转移来的,并且左端点单调不降。于是考虑使用单调队列优化DP,时间复杂度将至(O(nlogn)),期望得分(100pts)

    需要注意的是,在单调队列入队时,只能检查右端点是否符合要求,而不能检查左端点是否符合要求。检查左端点符合要求必须严格交给出队时检查,否则会导致入队指针卡在一个位置。

    即:在入队时写成

    while((pos < i) && ((MU[i].s-MU[pos].s) >= downfloor) && ((MU[i].s-MU[pos].s) <= upceil))
    

    是不对的,因为最后一个条件检查了左端点是否符合要求。

    while((pos < i) && ((MU[i].s-MU[pos].s) >= downfloor))
    

    才是正确的写法。

    Code

    #include<cstdio>
    #include<cstring>
    #define rg register
    #define ci const int
    #define cl const long long
    
    typedef long long ll;
    
    template <typename T>
    inline void qr(T &x) {
    	rg char ch=getchar(),lst=' ';
    	while((ch > '9') || (ch < '0')) lst=ch,ch=getchar();
    	while((ch >= '0') && (ch <= '9')) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    	if(lst == '-') x=-x;
    }
    
    namespace IO {
    	char buf[120];
    }
    
    template <typename T>
    inline void qw(T x,const char aft,const bool pt) {
    	if(x < 0) {x=-x,putchar('-');}
    	rg int top=0;
    	do {IO::buf[++top]=x%10+'0';} while(x/=10);
    	while(top) putchar(IO::buf[top--]);
    	if(pt) putchar(aft);
    }
    
    template <typename T>
    inline T mmax(const T a,const T b) {return a > b ? a : b;}
    template <typename T>
    inline T mmin(const T a,const T b) {return a < b ? a : b;}
    template <typename T>
    inline T mabs(const T a) {return a < 0 ? -a : a;}
    
    template <typename T>
    inline void mswap(T &_a,T &_b) {
    	T _temp=_a;_a=_b;_b=_temp;
    }
    
    const int maxn = 500010;
    
    int n,d,k,front,end;
    int que[maxn];
    ll frog[maxn];
    
    struct M {
    	int s,v;
    };
    M MU[maxn];
    
    bool check(int x);
    
    signed main() {
    	qr(n);qr(d);qr(k);
    	for(rg int i=1;i<=n;++i) {
    		qr(MU[i].s);qr(MU[i].v);
    	}
    	int r=100001,l=0,ans=-1,mid;
    	while(l <= r) {
    		mid=(l+r)>>1;
    		if(check(mid)) ans=mid,r=mid-1;
    		else l=mid+1;
    	}
    	qw(ans,'
    ',true);
    	return 0;
    }
    
    bool check(ci x) {
    	memset(frog,0,sizeof frog);
    	que[front=end=1]=0;
    	rg int upceil = d+x,downfloor=mmax(1,d-x);
    	rg int pos=1;
    	for(rg int i=1;i<=n;++i) {
    		while((pos < i) && ((MU[i].s-MU[pos].s) >= downfloor)) {
    			while((front <= end) && (frog[que[end]] <= frog[pos])) --end;
    			que[++end]=pos++;
    		}
    		while((front <= end) && (((MU[i].s-MU[que[front]].s)  > upceil))) ++front;
    		frog[i]=-1ll<<60;
    		if(front > end) continue;
    		if(MU[i].s-MU[que[front]].s < downfloor) continue;
    		frog[i]=frog[que[front]]+MU[i].v;
    		if(frog[i] >= k) return true;
    	}
    	return false;
    }
    
    

    Summary

    在单调队列入队时只能检查右端点,出队时只能检查左端点。

  • 相关阅读:
    webgl glsl
    javascript 分号理解
    流的理解 1
    javascript 排序
    phaser3 微信小游戏若干问题
    layabox 3d 入手
    phaser2 微信小游戏入手
    取整你知道几中办法?
    script 执行的三种方式
    cl查看类的内存布局
  • 原文地址:https://www.cnblogs.com/yifusuyi/p/9900196.html
Copyright © 2011-2022 走看看