题意
给一个双端队列,双方轮流取数,每一次能且只能从队头或队尾取数,取完数后将这个数从队列中弹出。双方都希望自己取的所有数之和尽量大,且双方都以最优策略行动,假设先手取的所有数之和为 X X X,后手取的所有数之和为 Y Y Y,求 X − Y X−Y X−Y。
1 ≤ N ≤ 3000 , 1 ≤ a i ≤ 1 0 9 1 ≤ N ≤ 3000,1 ≤ a_i≤ 10^9 1≤N≤3000,1≤ai≤109
思路
考虑反向区间dp,记 d p l , r dp_{l,r} dpl,r 表示剩下 [ l , r ] [l,r] [l,r] 未消除时,消除从 [ l , r ] [l,r] [l,r] 对答案的贡献。
显而易见,对于长度为 i i i 的区间 [ l , r ] [l,r] [l,r],如果 c n t − i cnt - i cnt−i 为奇数,则代表当前是对方取数,否则当前为己方取数。
对于对方取数时,有 d p l , r = min ( d p l , r − 1 − a r , d p l + 1 , r − a l ) dp_{l,r} = \min(dp_{l,r - 1} - a_r,dp_{l + 1,r} - a_l) dpl,r=min(dpl,r−1−ar,dpl+1,r−al)
对于己方取数时,有 d p l , r = max ( d p l , r − 1 + a r , d p l + 1 , r + a l ) dp_{l,r} = \max(dp_{l,r - 1} + a_r,dp_{l + 1,r} + a_l) dpl,r=max(dpl,r−1+ar,dpl+1,r+al)
容易发现答案为 d p 1 , n dp_{1,n} dp1,n。
代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,dp[3005][3005],a[3005];
int ans;
signed main() {
scanf("%lld",&n);
for(int i = 1;i <= n;i++) scanf("%lld",&a[i]);
for(int i = 1;i <= n;i++) {
for(int l = 1;l + i - 1 <= n;l++) {
int r = l + i - 1;
if((n - i) & 1) {
dp[l][r] = min(dp[l][r - 1] - a[r],dp[l + 1][r] - a[l]);
}
else dp[l][r] = max(dp[l][r - 1] + a[r],dp[l + 1][r] + a[l]);
//printf("(%lld,%lld)%lld\n",l,r,dp[l][r]);
}
}
printf("%lld\n",dp[1][n]);
}