dp Codeforces505C Mr. Kitayuta, the Treasure Hunter

来源:互联网 发布:大连海事大学网络下线 编辑:程序博客网 时间:2024/04/29 20:32

传送门:点击打开链接

题意:现在有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;}

1 0