题解 P3957 【跳房子】
思路
此题可以一眼看出可二分性
然后首先想到\(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;
}