链接:http://acm.dlut.edu.cn/problem.php?id=1328
直接贴代码:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 50;
ll arr[maxn],sum[maxn];
ll dp[maxn][3];
ll Max(ll a, ll b, ll c){
return max(max(a,b), c);
}
int main()
{
freopen("input.txt","r",stdin);
int T,i,n;
cin>>T;
while(T--){
memset(sum,0,sizeof(sum));
memset(dp,0,sizeof(dp));
cin>>n;
for(i=0;i<n;i++){
cin>>arr[i];
}
sum[n] = 0;
for(i=n-1;i>=0;i--){
sum[i] = sum[i+1] + arr[i];
}
if(n<=3){
cout<<sum[0]<<endl;
continue;
}
/*
dp[n-1][1] = arr[n-1];
dp[n-2][1] = arr[n-2];
dp[n-2][2] = arr[n-2] + arr[n-1];
dp[n-3][1] = arr[n-3];
dp[n-3][2] = arr[n-3] + arr[n-2];
dp[n-3][3] = arr[n-3] + arr[n-2] + arr[n-1];
*/
for(i=n-1;i>=0;i--){
dp[i][1] = sum[i+1] - Max(dp[i+1][1],dp[i+1][2],dp[i+1][3]) + arr[i];
dp[i][2] = sum[i+2] - Max(dp[i+2][1],dp[i+2][2],dp[i+2][3]) + arr[i] + arr[i+1];
dp[i][3] = sum[i+3] - Max(dp[i+3][1],dp[i+3][2],dp[i+3][3]) + arr[i] + arr[i+1] + arr[i+2];
}
ll ans = Max(dp[0][1],dp[0][2],dp[0][3]);
cout<<ans<<endl;
}
return 0;
}
原理:
dp[i][j]表示取从i位置起(包括i)的j个方块,所能达到的总共最大值。
递推公式,比如
dp[i][2] =
sum[i+2] //[i+2]~[n-1]块的数字和
- Max(dp[i+2][1],dp[i+2][2],dp[i+2][3]) //玩家B在[i+2]块起选一个最优策略
+ arr[i] + arr[i+1]; // 这是i起两个块
sum[i+2] //[i+2]~[n-1]块的数字和
- Max(dp[i+2][1],dp[i+2][2],dp[i+2][3]) //玩家B在[i+2]块起选一个最优策略
+ arr[i] + arr[i+1]; // 这是i起两个块
PS: 虽然是自己想出来的,但是并不太清楚dp这个数组为啥既能代表A的最优策略,也能代表B的最优策略。。他俩一个先手一个后手啊。。