Codeforces 505C
Mr. Kitayuta, the Treasure Hunter
题意:有n个宝藏分部在n个岛屿上,现在给出n个岛屿的位置,初始的时候你从0位置跳到位置为d的岛屿,往后每次跳跃的步长只能是上pre+1 pre pre-1 这3种(pre表示上一步的步长)
思路:dp+技巧优化空间
dp式很容易想到,dp[i][j]表示当前在第i个岛屿,上一步跳的步长为j,这样就得开3e4*3e4的数组,显然要爆内存,但是推一下很容易知道,1+2+3+...+250>3e4,也就是说步长最多有250种,即第二维有效的只有500个,所以可以在这个地方对空间经行优化,第二维表示上一步跳了j+d-250步,因此第二维只需要存j即可,还有一个问题是边界一定要处理好,下一步的位置一定要比当前的位置大,因为步长一定是正数
AC代码:
#include "iostream" #include "string.h" #include "stack" #include "queue" #include "string" #include "vector" #include "set" #include "map" #include "algorithm" #include "stdio.h" #include "math.h" #pragma comment(linker, "/STACK:102400000,102400000") #define ll long long #define endl ("\n") #define bug(x) cout<<x<<" "<<"UUUUU"<<endl; #define mem(a,x) memset(a,x,sizeof(a)) #define mp(x,y) make_pair(x,y) #define pb(x) push_back(x) #define ft (frist) #define sd (second) #define lrt (rt<<1) #define rrt (rt<<1|1) using namespace std; const long long INF = 1e18+1LL; const int inf = 1e9+1e8; const int N=3e4+10; const ll mod=1e9+7; int dp[N+100][600],v[N+100],n,d; int main(){ cin>>n>>d; for(int i=1; i<=n; ++i){ int x; cin>>x; v[x]++; } mem(dp,-1); dp[d][250]=v[d]; for(int i=d; i<=N; ++i){ for(int j=0; j<=500; ++j){ int nex=i+d+j-250; if(dp[i][j]==-1) continue; if(nex>i && nex<N) dp[nex][j]=max(dp[nex][j],dp[i][j]+v[nex]); if(nex-1>i && nex-1<N) dp[nex-1][j-1]=max(dp[nex-1][j-1],dp[i][j]+v[nex-1]); if(nex+1>i && nex-1<N) dp[nex+1][j+1]=max(dp[nex+1][j+1],dp[i][j]+v[nex+1]); } } int ans=0; for(int i=0; i<=N; ++i){ for(int j=0; j<=500; ++j){ ans=max(ans,dp[i][j]); } } cout<<ans<<endl; return 0; }