题解 P3957 【跳房子】

luogu

思路

此题可以一眼看出可二分性
然后首先想到\(check\)函数用\(dp\)

for(int i=1;i<=n;i++)
{
       for(int j=i-1;j>=0;j--)
       {
            if(a[i].s-a[j].s>d+g)
            {
                break;
            }
            if(a[i].s-a[j].s<=d+g && a[i].s-a[j].s>=max(d-g,1))
            {
                f[i]=max(f[i],f[j]+a[i].val);
            }
       }
}

但是复杂度是二维的显然会\(TLE\)
于是再看一眼题(ti)目(jie),开心地发现可以用单调队列优化
此时复杂度约等于线性(?)
可结合代码理解

Code

#include<bits/stdc++.h>
using namespace std;
long long n,d,k,x[500010],s[500010],f[500010],q[500010],head,tail;
long long Max(long long a,long long b)
{
	if(a>b)
		return a;
	return b;
}
int check(int g)
{
	head=1,tail=0;
	for(int i=0;i<=n;i++)
	{
		f[i]=0;
	}
	int j=0;
	for(int i=1;i<=n;i++)
	{
		for(;j<i&&x[i]-x[j]>=Max(1,d-g);j++)
		{
			for(;head<=tail;)
			{
				if(f[q[tail]]<=f[j])
					tail--;
				else
					break;
			}
			q[++tail]=j;
		}
		for(;head<=tail;)
		{
			if(x[i]-x[q[head]]>d+g)
				head++;
			else
				break;
		}
		for(;head<=tail;)
		{
			if(x[i]-x[q[tail]]<Max(1,d-g))
				tail--;
			else
				break;
		}
		if(head<=tail)
			f[i]=f[q[head]]+s[i];
		else
			f[i]=-1000000000000000;
		if(f[i]>=k)
			return 1;
	}
	return 0;
}
int main()
{
	//freopen("jump.in","r",stdin);
	//freopen("jump.out","w",stdout);
    scanf("%lld%lld%lld",&n,&d,&k);
    for(int i=1;i<=n;i++)
    {
    	scanf("%lld%lld",&x[i],&s[i]);
	}
	long long l=0,r=1000000; 
	while(l<=r)
	{
		long long mid=(l+r)/2;
		if(check(mid))
			r=mid-1;
		else
			l=mid+1;
	}
	if(check(l))
	{
		cout<<l;
		return 0;
	}
	cout<<-1;
	return 0; 
}
posted @ 2019-10-03 17:08  G_A_TS  阅读(388)  评论(0编辑  收藏  举报