大意: 给定$n$元素序列, 两个人从两端轮流拿数, 每一步假设对手上次取k, 那么只能取k或k+1, 先手第一步取1或2, 直到不能拿时停止. 先手要最大化两人数字和的差, 后手要最小化, 求最后差是多少.
显然状态数是$O(n^2)$的, 直接暴力DP
#include <iostream> #include <sstream> #include <algorithm> #include <cstdio> #include <math.h> #include <set> #include <map> #include <queue> #include <string> #include <string.h> #include <bitset> #define REP(i,a,n) for(int i=a;i<=n;++i) #define PER(i,a,n) for(int i=n;i>=a;--i) #define hr putchar(10) #define pb push_back #define lc (o<<1) #define rc (lc|1) #define mid ((l+r)>>1) #define ls lc,l,mid #define rs rc,mid+1,r #define x first #define y second #define io std::ios::sync_with_stdio(false) #define endl ' ' #define DB(a) ({REP(__i,1,n) cout<<a[__i]<<' ';hr;}) using namespace std; typedef long long ll; typedef pair<int,int> pii; const int P = 1e9+7, INF = 0x3f3f3f3f; ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;} ll qpow(ll a,ll n) {ll r=1%P;for (a%=P;n;a=a*a%P,n>>=1)if(n&1)r=r*a%P;return r;} ll inv(ll x){return x<=1?1:inv(P%x)*(P-P/x)%P;} inline int rd() {int x=0;char p=getchar();while(p<'0'||p>'9')p=getchar();while(p>='0'&&p<='9')x=x*10+p-'0',p=getchar();return x;} //head const int N = 4010; int n, a[N]; int *dp[2][N][N]; int o; int dfs(int tp, int l, int r, int k) { if (!dp[tp][l][r]) { int *p = new int[100]; memset(p,0x3f,sizeof(int)*100); dp[tp][l][r] = p; } int &ans = dp[tp][l][r][k]; if (ans!=INF) return ans; if (r-l+1<k) return ans=0; if (r-l+1==k) return ans=tp?a[r]-a[l-1]:a[l-1]-a[r]; if (tp==1) return ans=max(dfs(0,l+k,r,k)+a[l+k-1]-a[l-1],dfs(0,l+k+1,r,k+1)+a[l+k]-a[l-1]); return ans=min(dfs(1,l,r-k,k)-a[r]+a[r-k],dfs(1,l,r-k-1,k+1)-a[r]+a[r-k-1]); } int main() { scanf("%d", &n); REP(i,1,n) scanf("%d", a+i),a[i]+=a[i-1]; printf("%d ", dfs(1,1,n,1)); }