跳跃
题意:
每个点有一定黄金,从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; }