Description
有 n n 个石子,第个石子分数为 ai a i , Alice A l i c e 和 Bob B o b 轮流取石子, Alice A l i c e 先手,第一次 Alice A l i c e 可以拿左边的一个石子或两个石子,假设上一轮对手拿了 k k 个石子,这一轮就可以拿左边的个石子或 k+1 k + 1 个石子,当石子不够取时游戏结束,问游戏结束时 Alice A l i c e 得分与 Bob B o b 得分之差的最大值,游戏过程中 Alice A l i c e 采取使得分差尽可能大的方案, Bob B o b 采取使得分差尽可能小的方案
Input
第一行一整数 T T 表示用例组数,每组用例首先输入一整数表示石子个数,之后输入 n n 个整数表示这 n n 个石子的分数
Output
输出 Ailce A i l c e 与 Bob B o b 的分差
Sample Input
1
3
1 3 2
Sample Output
4
Solution
以 dp[0/1][i][j] d p [ 0 / 1 ] [ i ] [ j ] 表示 Alice/Bob A l i c e / B o b 从第 i i 个石子开始取且上一轮对手取了个最后可以得到的最大分差,以 si=∑j=1iaj s i = ∑ j = 1 i a j ,根据当前步取 j j 个或个石子有转移
dp[0][i][j]=max(si+j−1−si−1+dp[1][i+j][j],si+j−si−1+dp[1][i+j+1][j+1]) d p [ 0 ] [ i ] [ j ] = m a x ( s i + j − 1 − s i − 1 + d p [ 1 ] [ i + j ] [ j ] , s i + j − s i − 1 + d p [ 1 ] [ i + j + 1 ] [ j + 1 ] )
dp[1][i][j]=min(si−1−si+j−1+dp[0][i+j][j],si−1−si+j+dp[0][i+j+1][j+1]) d p [ 1 ] [ i ] [ j ] = m i n ( s i − 1 − s i + j − 1 + d p [ 0 ] [ i + j ] [ j ] , s i − 1 − s i + j + d p [ 0 ] [ i + j + 1 ] [ j + 1 ] )
注意到第 k k 轮最少也取了个石子,故 j≤2n−−√ j ≤ 2 n ,大约 200 200 左右,故第三维 200 200 即可,第二维滚动一下
由于先手可以取一个或两个石子,可以认为先手之前其对手取了一个分数为 0 0 的石子,故答案为
Code
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<ctime>
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
#define maxn 20005
int dp[2][255][255],T,n,a[maxn],sum[maxn];
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
sum[i]=sum[i-1]+a[i];
}
memset(dp,0,sizeof(dp));
int m=(int)sqrt(2.0*n+1),mod=233;
for(int i=n;i>=1;i--)
for(int j=m;j>=1;j--)
if(i+j-1<=n)
{
dp[0][i%mod][j]=sum[i+j-1]-sum[i-1]+dp[1][(i+j)%mod][j];
dp[1][i%mod][j]=sum[i-1]-sum[i+j-1]+dp[0][(i+j)%mod][j];
if(i+j<=n)
{
dp[0][i%mod][j]=max(dp[0][i%mod][j],sum[i+j]-sum[i-1]+dp[1][(i+j+1)%mod][j+1]);
dp[1][i%mod][j]=min(dp[1][i%mod][j],sum[i-1]-sum[i+j]+dp[0][(i+j+1)%mod][j+1]);
}
}
printf("%d\n",dp[0][1][1]);
}
return 0;
}