1. 程式人生 > >Codeforces Round #286 (Div. 1) A. Mr. Kitayuta, the Treasure Hunter DP

Codeforces Round #286 (Div. 1) A. Mr. Kitayuta, the Treasure Hunter DP

ret lan 超過 target div eof out ++ ces

鏈接:

http://codeforces.com/problemset/problem/506/A

題意:

給出30000個島,有n個寶石分布在上面,第一步到d位置,每次走的距離與上一步的差距不大於1,問走完一路最多撿到多少塊寶石。

題解:

容易想到DP,dp[i][j]表示到達 i 處,現在步長為 j 時最多收集到的財富,轉移也不難,cnt[i]表示 i 處的財富。

dp[i+step-1] = max(dp[i+step-1],dp[i][j]+cnt[i+step+1])

dp[i+step] = max(dp[i+step],dp[i][j]+cnt[i+step])

dp[i+step+1] = max(dp[i+step+1],dp[i][j]+cnt[i+step+1])

但是步長直接開30000存的話肯定是不行的,又發現,其實走過30000之前,步長的變化不會很大,如果步長每次增加1的話,那麽最少1+2+...+n=n(n+1)/2 > 30000, n<250,即步長變化不會超過250.所以第二維保存相對原始步長的改變量,-250~250,開500就夠了,這樣就不會MLE了。

代碼:

31 int n, d;
32 int a[MAXN];
33 int dp[MAXN][500];
34 
35 int main() {
36     ios::sync_with_stdio(false), cin.tie(0);
37     cin >> n >> d;
38 while (n--) { 39 int x; 40 cin >> x; 41 a[x]++; 42 } 43 memset(dp, -1, sizeof(dp)); 44 dp[d][250] = a[d]; 45 int ans = a[d]; 46 rep(i, d, 30001) rep(j, 1, 500) { 47 if (dp[i][j] == -1) continue; 48 int to = i + d + j - 250;
49 if (to <= 30000) { 50 dp[to][j] = max(dp[to][j], dp[i][j] + a[to]); 51 ans = max(ans, dp[to][j]); 52 } 53 if (to + 1 <= 30000) { 54 dp[to + 1][j + 1] = max(dp[to + 1][j + 1], dp[i][j] + a[to + 1]); 55 ans = max(ans, dp[to + 1][j + 1]); 56 } 57 if (to <= 30000 && to - i > 1) { 58 dp[to - 1][j - 1] = max(dp[to - 1][j - 1], dp[i][j] + a[to - 1]); 59 ans = max(ans, dp[to - 1][j - 1]); 60 } 61 } 62 cout << ans << endl; 63 return 0; 64 }

Codeforces Round #286 (Div. 1) A. Mr. Kitayuta, the Treasure Hunter DP