Description
有nn个石子,第个石子分数为aiai,AliceAlice和BobBob轮流取石子,AliceAlice先手,第一次AliceAlice可以拿左边的一个石子或两个石子,假设上一轮对手拿了kk个石子,这一轮就可以拿左边的个石子或k+1k+1个石子,当石子不够取时游戏结束,问游戏结束时AliceAlice得分与BobBob得分之差的最大值,游戏过程中AliceAlice采取使得分差尽可能大的方案,BobBob采取使得分差尽可能小的方案
Input
第一行一整数TT表示用例组数,每组用例首先输入一整数表示石子个数,之后输入nn个整数表示这nn个石子的分数
Output
输出AilceAilce与BobBob的分差
Sample Input
1
3
1 3 2
Sample Output
4
Solution
以dp[0/1][i][j]dp[0/1][i][j]表示Alice/BobAlice/Bob从第ii个石子开始取且上一轮对手取了个最后可以得到的最大分差,以si=∑j=1iajsi=∑j=1iaj,根据当前步取jj个或个石子有转移
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])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])
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])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])
注意到第kk轮最少也取了个石子,故j≤2n−−√j≤2n,大约200200左右,故第三维200200即可,第二维滚动一下
由于先手可以取一个或两个石子,可以认为先手之前其对手取了一个分数为00的石子,故答案为
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;
}