codeforces505C_记忆化搜索

题目链接http://codeforces.com/problemset/problem/505/C

题目大意:

现在有30000个岛,最开始站在第0个岛上,第一次向右跳d个岛。

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

思路:

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

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

最糟糕的情况,d为1,跳到第30000个岛要跳的次数为n, 有等式(1 + n) * n / 2 = 30000, 解出n大约等于250;[-250, 250], 所以dp[30010][500]就够了

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 using namespace std;
 6 
 7 const int N = 250;
 8 int n, d, a;
 9 int dp[30010][510], val[30010];//val[i]表示第i个岛有多少宝石
10 int find(int p, int f)//p为到达的岛
11 {
12     if(dp[p][N + f] != -1)//记忆化搜索关键
13         return dp[p][N + f];
14     int temp = 0;
15     for(int i = -1; i <= 1; i++)
16     {
17         if(d + f + i < 1 || p + d + f + i > 30000)//最初的步长d + (f + i)加减1后的总步数,如果小于1,说明跳的步数为0,不符合题意
18             continue;//为当前岛的编号p + (d + f + i)这次跳的步数,大于30000就不符合题意啦
19         temp = max(temp, find(p + d + f + i, f + i));
20         return dp[p][N + f] = temp + val[p];
21 }
22 int main()
23 {
24     scanf("%d %d", &n, &d);
25     memset(val, 0, sizeof(val));
26     for(int i = 1; i <= n; i++){
27         scanf("%d", &a);
28         val[a]++;
29     }
30     memset(dp, -1, sizeof(dp));
31     printf("%d\n", find(d, 0));
32     return 0;
33 }

 

posted @ 2016-05-29 21:22  海无泪  阅读(406)  评论(0编辑  收藏  举报