跳跃

题意:

每个点有一定黄金,从0开始跳,如果上一次跳了l,这一次可以跳l,l-1,l+1,问最多可以拿多少

n<=30000 512mb,1s

题解:

f[i][j]表示状态显然

注意到状态有很多达不到

于是用了记忆化搜索

改成链式hash加上一些剪枝勉强可以卡过

考虑用dp来写

我们会发现l的偏移量其实是不大的

假设每次-1,l....x (l+x)(l-x+1)/2 解得x是l-根号n的

所以我们可以把j变成偏移量,时间复杂度n根号n

hash的复杂度其实也挺高的,常数大概有10倍

#include <bits/stdc++.h>
using namespace std;
#define rint register int
#define IL inline
#define rep(i,h,t) for (rint i=h;i<=t;i++)
#define dep(i,t,h) for (rint i=t;i>=h;i--)
const int N=4e4;
int n,m,f[N],l,n1,cnt,sum[N],ans1;
IL void maxn(rint &x,rint y)
{
  if (x<y) x=y;
}
const int mo=3e7+1;
struct re{
  int a,b,c;
}a[mo+10];
int head[mo+10];
struct hash{
  IL int find(rint x)
  {
    for (rint u=head[x%mo];u;u=a[u].a)
      if (a[u].b==x) return(a[u].c);
    return(0);
  }
  IL void push(rint x,rint z)
  {
    rint y=x%mo;
    a[++l].a=head[y];
    a[l].b=x;
    a[l].c=z;
    head[y]=l;
  }
}hash;
int dfs(rint x,rint y,rint z)
{
  if (sum[n1]-sum[x-1]+z<=ans1) return(0);
  if (x>n1) return(0);
  rint ans1=hash.find((x+1)*30001+y);
  if (ans1) return(ans1);
  rint ans=0;
  if (y!=1) maxn(ans,dfs(x+y-1,y-1,z+f[x]));
  maxn(ans,dfs(x+y,y,z+f[x]));
  maxn(ans,dfs(x+y+1,y+1,z+f[x]));
  ans+=f[x];
  hash.push((x+1)*30001+y,ans);
  ans1=max(ans1,ans);
  return(ans); 
}
int main()
{
  freopen("1.in","r",stdin);
  freopen("1.out","w",stdout);
  ios::sync_with_stdio(false);
  cin>>n>>m;
  rep(i,1,n)
  {
    int x; cin>>x; f[x]++;
    n1=max(n1,x);
  }
  rep(i,1,n1) sum[i]=sum[i-1]+f[i];
  cout<<dfs(m,m,0)<<endl;
  cout<<cnt;
  return 0;
}

 

posted @ 2018-08-12 14:15  尹吴潇  阅读(143)  评论(0编辑  收藏  举报