本题直接使用dfs,然后配合剪枝去接最好。直接dfs的去进行每一步当递归到最大的拥有宝藏的岛屿的下一个就可以宣布结束返回了。
如何剪枝:本题中dfs是从前向后的传参形的记录当前的宝藏数量,那么如果某个岛屿第二遍被递归到的时候如果当前的宝藏数还没有之前的大。那么再递归下去就没有意义了。
这是我看别人的AC代码得出来的,但是我觉得这个剪枝有些问题,在这里面决定后面情况的不止是他当前在哪个岛屿还有当前到达这个岛屿跨越了多少,这个东西可以决定以后的步伐。所以单纯的用当前岛屿的最大宝藏数取判断总感觉有些问题。
我自己一开始写的是记忆化搜索,但是只过了80%就是因为记忆性剪枝的时候没考虑到步伐的情况。但最后也没能改成AC。。。。。
//使用记忆化搜索。
#include <bits/stdc++.h>


using namespace std;
const int maxn = 30000+10;
// int dp[maxn];
int f[maxn];
// bool vis[maxn];
int jewel[maxn];
int n,d, dmax;
int res = 0;
void dfs(int now, int l, int y) {
//     cout<<now<<endl;
    if (now>dmax) {
        return ;
    }
    y += jewel[now];
    if (y<f[now]) return ;
//     if (vis[now]) {
//         return dp[now];
//     }
    res=max(res,y);
    f[now]=max(f[now],y);
    for (int i=-1;i<2;i++) {
        int next = now+i+l;
        if (next-now>=1)
        {
            dfs(next, i+l, y);
        }
    }
//     vis[now] = true;
//     return dp[now];
}

int main() {
    cin>>n>>d;
    int k;
    for (int i=1;i<=n;i++) {
        cin>>k;
        jewel[k]++;
        dmax = max(k, dmax);
    }
    dfs(d, d, 0);
//     int ans =0 ;
//     for (int i=0;i<=30000;i++) {
//         ans = max(ans, dp[i]);
//     }
//     cout<<ans+jewel[0];
    cout<<res<<endl;
    return 0;
}