来源:牛客网:

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述

The Shuseki Islands are an archipelago of 30001 small islands in the Yutampo Sea. The islands are evenly spaced along a line, numbered from 0 to 30000 from the west to the east. These islands are known to contain many treasures. There are n gems in the Shuseki Islands in total, and the i-th gem is located on island pi.

Mr. Kitayuta has just arrived at island 0. With his great jumping ability, he will repeatedly perform jumps between islands to the east according to the following process:

First, he will jump from island 0 to island d.
After that, he will continue jumping according to the following rule. Let l be the length of the previous jump, that is, if his previous jump was from island prev to island cur, let l = cur - prev. He will perform a jump of length l - 1, l or l + 1 to the east. That is, he will jump to island (cur + l - 1), (cur + l) or (cur + l + 1) (if they exist). The length of a jump must be positive, that is, he cannot perform a jump of length 0 when l = 1. If there is no valid destination, he will stop jumping.
Mr. Kitayuta will collect the gems on the islands visited during the process. Find the maximum number of gems that he can collect.

输入描述:
The first line of the input contains two space-separated integers n and d (1 ≤ n, d ≤ 30000), denoting the number of the gems in the Shuseki Islands and the length of the Mr. Kitayuta's first jump, respectively.

The next n lines describe the location of the gems. The i-th of them (1 ≤ i ≤ n) contains a integer pi (d ≤ p1 ≤ p2 ≤ ... ≤ pn ≤ 30000), denoting the number of the island that contains the i-th gem.

输出描述:
Print the maximum number of gems that Mr. Kitayuta can collect.

示例1
输入
复制

4 10
10
21
27
27

输出
复制

3

示例2
输入
复制

8 8
9
19
28
36
45
55
66
78

输出
复制

6

示例3
输入
复制

13 7
8
8
9
16
17
17
18
21
23
24
24
26
30

输出
复制

4

备注:

In the first sample, the optimal route is 0  →  10 (+1 gem)  →  19  → 
27 (+2 gems)  → ...

In the second sample, the optimal route is 0  →  8  →  15  →  21 →  28
(+1 gem)  →  36 (+1 gem)  →  45 (+1 gem)  →  55 (+1 gem)  →  66 (+1
gem)  →  78 (+1 gem)  → ...

In the third sample, the optimal route is 0  →  7  →  13  →  18 (+1
gem)  →  24 (+2 gems)  →  30 (+1 gem)  → ...

题意:

一维坐标共有30001个,坐标从0~30000,其中有n个坐标有宝座,起始点为0,给出第一步跳跃距离d,之后每一步可以从上一步x的基础上选择x,x-1,x+1。
问最多能拿多少宝藏?

题解:

第一反应是dp
dp[i][j]表示到达第i个岛屿,跳的距离为j得到的最大宝藏数
从上一次状态之后,可以跳三种情况,j,j+1,j-1,由此可得
dp[i+j][j]=max(dp[i+j][j],dp[i][j]+c[i+j])
dp[i+j+1][j+1]=max(dp[i+j+1][j+1],dp[i][j]+c[i+j+1])
dp[i+j-1][j-1] = max(dp[i+j-1][j-1], dp[i][j] + c[i+j-1])
我们将上面三个式子可以整合在一起:
dp[i][j]=max(dp[i][j],dp[next][j+k]+gem[i])
k的范围是-1~1
next=i -( j + d - 250 )

第一维数组开30000
第二维不能再开这么大,
我们算一算最大步长为1+2+3+...a+250 > 30000,所以最大也就是从第一次d的基础上上下浮动250,所以开500+够用
我们规定 j=250 时表示和d相等,每次可以跳d,d-1,d+1,而下下次又是再上次基础上加减1和不变,所以( j -250 )+d表示当前跳跃的距离,i-(j-250)-d表示上一次的位置

代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=30013;
int gem[maxn];
int dp[maxn][520];
int main()
{
    int n,d;
    cin>>n>>d;
    int sum=0;
    for(int i=1;i<=n;i++)
    {
        int x;
        cin>>x;
        gem[x]++;//记录宝藏坐标数量 
     } 
     memset(dp,-1,sizeof(dp));
     dp[d][250]=gem[d];//相当于把250当做0步
     //每次移动就是250上下浮动 
     for(int i=d;i<=30000;i++)//i表示当前距离 
     {
         for(int j=1;j<=500;j++)
         {
             int jump=(j+d-250);//表示跳的距离 
             int next=i-jump;//表示上一次的位置 
             if(next<0||next>=i)continue;//不往回跳 
             //上一次的位置一定在当前位置之前,否则成了向后跳
             for(int k=-1;k<=1;k++)
             {
                 if(j+k>0&&dp[next][j+k]!=-1)dp[i][j]=max(dp[i][j],dp[next][j+k]+gem[i]);//转移方程 
             }
             sum=max(sum,dp[i][j]);
        }

     }
     cout<<sum<<endl;
     return 0;
}