当前位置: 代码迷 >> 综合 >> dp Codeforces505C Mr. Kitayuta, the Treasure Hunter
  详细解决方案

dp Codeforces505C Mr. Kitayuta, the Treasure Hunter

热度:41   发布时间:2023-12-14 03:26:33.0

传送门:点击打开链接

题意:现在有3w个点,最开始站在第0个点上,第一次会向右跳d个点。

若上一次为d,这次只能向右跳d-1,d,和d+1步。步数不能为0,当不能向右跳时即停止。

思路:不考虑时间和空间,最朴素的方法就是设dp[i][j]表示上一步跳了j步,当前在i点上,之后的转移也很好写

然而这明显是会爆时间爆空间的,不过我们可以发现,二维的j并不需要等于30000,而只会在[d-245,d+245]这个范围内!

因为,最差情况下,它的步数逐渐增大,那么会形成等差数列,所以x*(x-1)/2<=d,可以很容易得到x的变化并不会太大。

在上面我们证明了复杂度,所以接下来只要直接用记忆化搜索就能写完了,不过有个地方要注意,cf上的G++默认的栈是满的,但是codeblocks的栈不是满的,所以在本地测试会爆栈,不过提交的时候是不会爆的。

  

#include<map>
#include<set>
#include<cmath>
#include<ctime>
#include<stack>
#include<queue>
#include<cstdio>
#include<cctype>
#include<string>
#include<vector>
#include<cstring>
#include<iomanip>
#include<iostream>
#include<algorithm>
#include<functional>
#define fuck(x) cout<<"["<<x<<"]"
#define FIN freopen("input.txt","r",stdin)
#define FOUT freopen("output.txt","w+",stdout)
using namespace std;
typedef long long LL;
typedef pair<int, int>PII;const int MX = 3e4 + 5;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;const int P = 250;
int dp[MX][500], val[MX], n, d;
int DP(int p, int b) {if(dp[p][P + b] != -1) return dp[p][P + b];int ret = 0;for(int i = -1; i <= 1; i++) {if(d + b + i < 1 || p + d + b + i > 30000) continue;ret = max(ret, DP(p + d + b + i, b + i));}return dp[p][P + b] = ret + val[p];
}
int main() {//FIN;while(~scanf("%d%d", &n, &d)) {memset(dp, -1, sizeof(dp));memset(val, 0, sizeof(val));for(int i = 1; i <= n; i++) {int t; scanf("%d", &t);val[t]++;}printf("%d\n", DP(d, 0));}return 0;
}