题意:n颗硬币 两个人从前往后按顺序拿
如果上一个人拿了i颗 那么下一个可以拿1-2*i颗
问先手能获得的最大收益
题解:比较典型的最大最小最大最小..DP了
但是暴力做的话是n^3 所以就体现出了这个题的巧妙之处
dp[i][j]表示拿到了第i颗上一个人拿了j颗
dp[i][j]由 dp[i + k][k] k = 1,2...2 * j转移来
dp[i][j - 1]由 dp[i + k][k] k = 1,2...2 * (j - 1)转移来
有许多状态是一样的 所以dp[i][j-1]可以转移到dp[i][j] 再枚举两个新的状态
显然要倒着dp
#include <bits/stdc++.h> using namespace std; int sum[2005]; int dp[2005][2005]; int main() { int n; scanf("%d", &n); for(int i = 1; i <= n; i++) scanf("%d", &sum[i]), sum[i] += sum[i - 1]; for(int i = i; i <= n; i++) dp[n][i] = sum[n] - sum[n - 1]; for(int i = n - 1; i >= 1; i--) { for(int j = 1; j <= n; j++) { dp[i][j] = dp[i][j - 1]; int k = (j - 1) * 2 + 1; if(i + k <= n) dp[i][j] = max(dp[i][j], sum[n] - sum[i - 1] - dp[i + k][k]); else dp[i][j] = max(dp[i][j], sum[n] - sum[i - 1]); k++; if(i + k <= n) dp[i][j] = max(dp[i][j], sum[n] - sum[i - 1] - dp[i + k][k]); else dp[i][j] = max(dp[i][j], sum[n] - sum[i - 1]); } } printf("%d ", dp[1][1]); return 0; }