题目链接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 ", find(d, 0)); 32 return 0; 33 }