[ABC303G] Bags Game 题解
一、题目大意
Takahashi(先手)和 Aoki(后手)在玩游戏。他们有无限的钱,从左到右一共有
- 拿走最左边或者最右边的物品。
- 付给 Snuke
A 块钱,然后拿走最左边和最右边的共\min(B,n) 个物品。 - 付给 Snuke
C 块钱,然后拿走最左边和最右边的共\min(D,n) 个物品。
定义一个人的最大收益是拿到的所有东西的价值之和减去付给 Snuke 的钱数。
请问如果
-
1\le B,D\le N\le 3000,A,C\le 10^9
二、做法
部分来自官方题解。
1. 确定算法
面对这种双方轮流从一个序列两端取走物品并且要最大化自己的收益减去对方的收益的策略游戏,我们一般直接选择区间 dp。
2. 状态设计
令
3. 状态转移
依据题意直接写。
总时间复杂度
4. 优化转移
我们可以将
我们发现,对于固定的
当然还有
三、代码
#include<bits/stdc++.h>
#define S(p,q) s[p+q-1]-s[q-1]
#define V(p,q) (S(p,q)+f[p][q])
using namespace std;
typedef long long ll;
ll f[3010][3010],n,A,B,C,D,s[3010],x[3010],q[3010];
inline void cal(ll k,ll i,ll Z){
for(ll j=1,h=1,t=0;j<=n+1-k;j++){
while(h<=t&&V(k,q[t])>=V(k,j))t--;
q[++t]=j;
while(h<t&&q[h]<j+k-i)h++;
if(j+k>i)f[i][j+k-i]=max(f[i][j+k-i],S(i,j+k-i)-Z-V(k,q[h]));
}
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>n>>A>>B>>C>>D;
for(ll i=1;i<=n;i++)cin>>x[i],s[i]=s[i-1]+x[i];
for(ll i=1;i<=n;i++){
for(ll j=1;j<=n+1-i;j++)f[i][j]=max(x[j]-f[i-1][j+1],x[i+j-1]-f[i-1][j]);
cal(i-min(i,B),i,A);cal(i-min(i,D),i,C);
}
cout<<f[n][1]<<'\n';
return 0;
}