NOIP2017 跳房子(单调队列优化DP+二分)

50分做法:

可以发现答案具有单调性,所以二分答案。判断是否可行就需要DP。dp[i]表示到第i个格能得的最大值,从能跳向它的格进行转移即可。

#include<cstring>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<cstdio>
using namespace std;
typedef long long ll;
const int maxm=500007;
int n,d,k;
struct node
{
 int x,z;
}a[maxm];
int ans=-1;
ll dp[maxm];
bool check(int x)
{
  int maxx,minn;
  if(x<d)
  minn=d-x;
  else minn=1;
  maxx=d+x;
  memset(dp,-0x3f,sizeof(dp));
  dp[0]=0;
  for(int i=1;i<=n;i++)
  {
    for(int j=0;j<=i-1;j++)
    {
     if((a[i].x-a[j].x)<minn||(a[i].x-a[j].x)>maxx) continue;
	 dp[i]=max(dp[i],dp[j]+a[j].z);	
    }
  }
  ll tot=-1e15;
  for(int i=0;i<=n;i++)
  {
     tot=max(tot,dp[i]);
  }
  if(tot>=k) return 1;
  else return 0;
}
int main()
{
 scanf("%d%d%d",&n,&d,&k);
 for(int i=1;i<=n;i++)
 scanf("%d%d",&a[i].x,&a[i].z);
 int l=0,r=a[n].x;
 while(l<=r)
 {
  int mid=(l+r)>>1;
  if(check(mid))
  {
    ans=mid;
    r=mid-1;
  }
  else
  l=mid+1; 
 }
 printf("%d\n",ans);
 return 0;
}

满分做法:

50分做法的转移是O(\(n\sqrt{n}\))的,如何更快的转移呢?因为随着格的转移,能被跳到的区间也在转移,而且他一定是从这个区间中的最大值转移过来。

嗯!单调队列即可。

#include<cstring>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<cstdio>
using namespace std;
typedef long long ll;
const int maxm=500007;
int n,d,k;
struct node
{
 int x,z;
}a[maxm];
int ans=-1;
ll dp[maxm];
int q[maxm];
bool check(int x)
{
  int maxx,minn;
  if(x<d)
  minn=d-x;
  else minn=1;
  maxx=d+x;
  memset(dp,-0x3f,sizeof(dp));
  dp[0]=0;
  int j=0;
  int h=1,t=0;
  for(int i=1;i<=n;i++)
  {
    for(;a[j].x+minn<=a[i].x;j++)
    {
      while(h<=t&&dp[q[t]]<=dp[j]) t--;//维护一个单调递减的队列 
	  q[++t]=j;	
    }
    while(h<=t&&a[q[h]].x+maxx<a[i].x) h++;
    if(h<=t) dp[i]=dp[q[h]]+a[i].z;
    if(dp[i]>=k) return 1;
  }
  return 0;
}
int main()
{
 scanf("%d%d%d",&n,&d,&k);
 for(int i=1;i<=n;i++)
 scanf("%d%d",&a[i].x,&a[i].z);
 int l=0,r=a[n].x;
 while(l<=r)
 {
  int mid=(l+r)>>1;
  if(check(mid))
  {
    ans=mid;
    r=mid-1;
  }
  else
  l=mid+1; 
 }
 printf("%d\n",ans);
 return 0;
}
posted @ 2019-10-16 17:59  lihan123  阅读(196)  评论(0编辑  收藏  举报