题意

有30000个岛屿,某些岛屿上有一些宝石,第一次跳到了d号岛上,每次跳跃的距离与上一次跳跃的距离之差不超过1,问你最多可以收集多少宝石。

分析

我们可以定义 dp[i][j] 表示为跳到第 i 个岛屿,且上一次跳跃距离为 j ,那么显然有



但是这样做,显然时间和空间都不够。

我们可以发现,第一步和最后一步的差值不会超过 250 ,因为1+2+3+...+250 > 30000

那么我们可以定义 dp[i][j] 表示跳到第 i 个岛屿,且与第一次跳跃距离的差值为 j-250 。

#include <bits/stdc++.h>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
#define pii pair<int,int>
const int inf = 0x3f3f3f3f;
const int maxn = 30010;
const int M = 1e9+7;
int n,m,d;

int a[maxn],dp[maxn][550];      //到第i个岛,上一步走了d+(j-250)远

signed main()
{
    ios::sync_with_stdio(false);cin.tie(0);
    cin>>n>>d;
    for(int i = 1,x; i <= n; i++) 
    {   
        cin>>x;
        a[x]++;
        m = max(m,x);
    }
    mem(dp,-1);dp[d][250] = a[d];
    int ans = a[d];
    for(int i = d; i <= m; i++)
    {
        for(int j = 1; j <= 500;j++)
        {
            if(dp[i][j] == -1) continue;
            int to = i+d+j-250;
            //l
            if(to > i && to <= 30000)
            {
                dp[to][j] = max(dp[to][j],dp[i][j]+a[to]);
                ans = max(ans,dp[to][j]);
            }
            //l-1
            if(to-1 > i && to-1 <= 30000)
            {   
                dp[to-1][j-1] = max(dp[to-1][j-1],dp[i][j]+a[to-1]);
                ans = max(ans,dp[to-1][j-1]);
            }
            //l+1
            if(to+1 > i && to+1 <= 30000)
            {
                dp[to+1][j+1] = max(dp[to+1][j+1],dp[i][j]+a[to+1]);
                ans = max(ans,dp[to+1][j+1]);
            }
        }
    }
    cout<<ans<<endl;
    return 0;
}