题意:有一串长度为m数列,两个人轮流从左边开始拿数字,每次可以拿k(2-m)个数字,然后这人会获得相当于这k个数之和的score,然后这k个数变成一个数,也即他们的和在数列的最左边,两个是都想最大化自己和他人的差距,也即是的score(自己的)-score(对面的)最大,然后游戏当只剩下一个数的时候停止
题解:
这个和之前的一题很像http://blog.youkuaiyun.com/sjtsjt709/article/details/53326892
dp[i]记录1-i已经被合并的情况下,当前取数的人先手所能取得的和另一人的最大差值
很明显dp[i]=max(sum[j]-dp[j])(i<j<=n)
因为当前人拿多少个数显然是可以由自己决定的
然后记忆化搜索或者从后往前dp,顺带记录max(sum[j]-dp[j])(i<j<=n)
吐槽:
当时我做这题的时候这样考虑
dp[i][0]代表第一个人取完时 [1..i]合并了 score[0]-score[1]的最大值
dp[i][0]=max(sum[i]-dp[j][1])(1<=j<i)
dp[i][1]=max(sum[i]-dp[j][0])(1<=j<i)
其实本质上这个方程是错的,但我还是看了很久
错的原因是:我取数的时候取得是max(sum[i]-dp[j][1]),然而这是建立在对方会取到j,使得[1..j]合并的情况下,也就是我想当然了
但双方都是聪明人,都 play optimally,所以这个方程本质上就是错的
所以这种类似博弈,双方都取最优解 play optimally的情况,一般是从后往前推
#include<set>
#include<map>
#include<cmath>
#include<stack>
#include<queue>
#include<bitset>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define PB push_back
#define MP make_pair
#define ll long long
#define MS(a,b) memset(a,b,sizeof(a))
#define LL (rt<<1)
#define RR (rt<<1|1)
#define lson l,mid,LL
#define rson mid+1,r,RR
#define pii pair<int,int>
#define pll pair<ll,ll>
#define lb(x) (x&(-x))
void In(){freopen("in.in","r",stdin);}
void Out(){freopen("out.out","w",stdout);}
const int N=2e5+10;
const int M=3e5+10;
const int Mbit=1e6+10;
const int inf=0x3f3f3f3f;
const ll mod=1e9+7;
int dp[N],a[N],s[N];
int main()
{
int n;
while(~scanf("%d",&n)){
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=1;i<=n;i++)s[i]=s[i-1]+a[i];
int mx=s[n];
for(int i=n-1;i>=1;i--){
dp[i]=mx;
mx=max(mx,s[i]-dp[i]);
}
printf("%d\n",dp[1]);
}
return 0;
}