何老板最近在玩一款收集宝石的手游。游戏虽然简单,但他仍然乐此不疲。
游戏中,有300013000130001个小岛排成一条直线,小岛从左往右编号000到300003000030000,相邻岛屿间距为111。
有nnn块宝石分布在这些岛上,其中第iii块宝石分布在PiPiPi号岛上。
游戏规则如下:
游戏开始时,游戏角色小飞侠位于000号小岛。何老板操控小飞侠往右飞行。
第111次飞行距离只能是ddd米。也就是第一次飞行只能飞到d号小岛去着陆。
第i(i>1)i(i>1)i(i>1)次飞行的距离可从Len−1,Len,Len+1Len-1, Len, Len+1Len−1,Len,Len+1中任选一个。LenLenLen是第i−1i-1i−1次飞行的距离。
如果没法继续往右飞行了,游戏结束。
每着陆到一个岛上,小飞侠就可以收集该岛上的所有宝石。何老板想知道,他最多能获得多少块宝石。
输入格式:
第一行,两个整数nnn和ddd,
1 ≤ n, d ≤ 300001 ≤ n, d ≤ 300001 ≤ n, d ≤ 30000
接下来nnn行,每行一个整数,其中第i行表示第i块宝石所在的小岛的编号PiPiPi。
1 ≤ i ≤ n1 ≤ i ≤ n1 ≤ i ≤ n
d ≤ P1 ≤ P2 ≤ ... ≤ Pn ≤ 30000d ≤ P1 ≤ P2 ≤ ... ≤ Pn ≤ 30000d ≤ P1 ≤ P2 ≤ ... ≤ Pn ≤ 30000
输出格式:
一个整数,表示何老板最多能够收集到的宝石数量
解:
我们对于这道题,有一个十分显然的方式:
设f[i][j]f[i][j]f[i][j]表示从iii号岛出发,出发的速度为jjj
很显然有一个方程:
f[i][j]=max{f[i+j][j]i+j<= 30000f[i+j+1]j+1]i+j+1<= 30000f[i+j−1][j−1]j>1f[i][j]=\max\left\{ \begin{array}{ll}
f[i+j][j] & \textrm{i+j<= 30000} \\
f[i+j+1]j+1] &\textrm{i+j+1<= 30000}\\
f[i+j-1][j-1] &\textrm{j>1}
\end{array}\right.f[i][j]=max⎩⎨⎧f[i+j][j]f[i+j+1]j+1]f[i+j−1][j−1]i+j<= 30000i+j+1<= 30000j>1
但是显然我们发现这样时间复杂度是O(nd)O(nd)O(nd)
在 300002 30000^2 300002的数字我们显然放弃。
但是我们突然发现。
为什么题目说的是300013000130001?为什么要固定?
我们来考虑下ddd的偏移量。
我们惊奇地发现:
∑1245>30001\sum_{1}^{245}>300011∑245>30001
考虑了一下,所以说在实际决策中我们用到的速度其实只有500500500种(约等于490490490)
这就把第二维降到了500500500的程度
#include<bits/stdc++.h>
using namespace std;
template<typename T>
void rin(T &t)
{t=0;int k=1;char c=getchar();while(!isdigit(c)){if(c=='-')k=-1;c=getchar();}while(isdigit(c)){t=t*10+c-'0';c=getchar();}t*=k;}
typedef long long ll;
const int maxn=30001+5;
int pos[maxn],a[maxn],n,d,ans,f[maxn][505];
int dp(int x,int dv)
{
int v=dv-250+d;
if(x>pos[n])return 0;
if(f[x][dv]!=-1)return f[x][dv];
f[x][dv]=0;
f[x][dv]=max(f[x][dv],dp(x+v+1,dv+1));
f[x][dv]=max(f[x][dv],dp(x+v,dv));
if(v>1)f[x][dv]=max(f[x][dv],dp(x+v-1,dv-1));
f[x][dv]=f[x][dv]+a[x];
return f[x][dv];
}
int main()
{
rin(n);rin(d);
memset(f,-1,sizeof(f));
for(int i=1;i<=n;i++){rin(pos[i]);a[pos[i]]++;}
cout<<dp(d,250);
return 0;
}