题面
题意
给出一个序列,两人轮流从一端开始取任意个数,最后所取数的和即为得分,两人都想要较高得分,则先去者的最高得分是多少。
做法
首先不难想到用dp[i][j]表示序列剩下从i到j这段时的最高得分,这样的话有n^2种状态,n的状态转移,总复杂度为n^3,会T。
因此可以考虑记录下述值:
le[i][j]表示从左边开始取,剩下的数取到的最高分的最小值,也就是说:
le[i][j]=min(dp[i+1][j],dp[i+2][j],……+dp[j][j])
因此,le[i][j]=min(le[i+1][j],dp[i][j]).
ri[i][j]也同理。
只要枚举长度然后递推即可。
代码
#include<iostream>
#include<cstdio>
#define ll long long
#define N 1010
using namespace std;
ll T,n,num[N],dp[N][N],le[N][N],ri[N][N],qz[N];
int main()
{
ll i,j,l;
cin>>T;
while(T--)
{
scanf("%lld",&n);
qz[0]=0;
for(i=1;i<=n;i++)
{
scanf("%lld",&num[i]);
dp[i][i]=le[i][i]=ri[i][i]=num[i];
qz[i]=qz[i-1]+num[i];
}
for(l=1;l<=n;l++)
{
for(i=1,j=l;j<=n;i++,j++)
{
dp[i][j]=qz[j]-qz[i-1]-min(le[i+1][j],ri[i][j-1]);
le[i][j]=min(le[i+1][j],dp[i][j]);
ri[i][j]=min(ri[i][j-1],dp[i][j]);
}
}
printf("%lld\n",dp[1][n]);
}
}