题意
一共有30000个位置,从第0个位置开始走,第一次走k步,对于每一次走步,可以走上一次的ki+1 ,ki ,ki-1步数(必须大于等于1),每个岛上有value,求最大能得到的value能有多少。
分析
一开始我想用搜索做,然后一直会T,看了题解才知道是用dp来做,感觉最后自己还是写的挺搓的_(:з」∠)_。
首先可以证明出每一步的步数与第一次的步数差值不会超过250。
开一个二维dp数组,dp[i][j]代表在第i个位置,前一步走了(j-250+k)步数
所以dp转移方程为
if(j-250+k>1)//当走到这里的步数大于1时,当前步的上一步有三种可能
dp[i][j] := max(dp[i-(j+k-250)][j], max(dp[i-(j+k-250)][j-1] , dp[i-(j+k-250)][j+1])) + wei[i];
else//当走到这里的步数等于1时,当前步的上一步只能是1或者2
dp[i][j] := max(dp[i-(j+k-250)][j],dp[i-(j+k-250)][j+1]) + wei[i];
#include <iostream> #include <cstdio> #include <cstring> #include <queue> #include <algorithm> using namespace std; #define MAX_NUM 60007 #define MAX_STP 509 #define INF 0x3f3f3f3f int dp[MAX_NUM][MAX_STP]; int wei[MAX_NUM]; int main(int argc, char const *argv[]) { int n, k; scanf("%d%d",&n,&k); int num; int ansnum = 0; for (int i = 0; i < n ; ++i) { scanf("%d",&num); wei[num]++; ansnum = max(ansnum,num); } memset(dp,-INF,sizeof(dp)); dp[k][250] = wei[k]; int ans = wei[k]; for (int i = k+1; i <= ansnum ; ++i) { for (int j = max(1,251-k); j <= 500 ; ++j) { if(j == 251 - k) dp[i][j] = max(dp[i-(j+k-250)][j],dp[i-(j+k-250)][j+1]) + wei[i]; else if(i-(j+k-250)>=k){ dp[i][j] = max(dp[i-(j+k-250)][j], max(dp[i-(j+k-250)][j-1] , dp[i-(j+k-250)][j+1])) + wei[i]; } else break; ans = max(ans,dp[i][j]); } } printf("%d ",ans ); return 0; }