传送门。
题意
应该是显然的.
分析
首先,观察数据范围:\(1\le n\le 3000\),也就是说,时间复杂度应当在 \(O(n^2)\) 左右。
其次,观察我们取球的顺序,是只能从左或右取,因此,我们每次留下的必然是连续的一段。
所以,我们显然可以采用区间 DP 来解决这道题。
确定状态:\(f_{i,j}\) 表示现在取了剩下 \(i\sim j\),先手的最大得分。
考虑转移:由于我们是先后手易手的取数,所以我们当前的状态是从小 \(1\) 的区间的对立面转移过来,这里有两种方式,一种是直接记录对立面,另一种,我们可以记录区间能够取到的价值的总和,显然这个是和取法无关的。
#include <bits/stdc++.h>
//#define int long long
using namespace std;
const int N = 3e3+5;
inline int read() {
int x;
scanf("%d",&x);
return x;
}
int n, m,a[N],qzh[N][N],tot[N][N],fr[N],en[N],f[N][N];
inline int val(int L,int R,int x) {
if(x) return L<=fr[a[R]]&&(en[a[R]]==R);
else return (fr[a[L]]==L)&&en[a[L]]<=R;
}
signed main() {
n=read();
memset(fr,0x3f,sizeof fr);
for(int i=1; i<=n; ++i) a[i]=read(),fr[a[i]]=min(fr[a[i]],i),en[a[i]]=i;
for(int i=1; i<=n; ++i) for(int j=1; j<=n; ++j) qzh[i][j]=qzh[i-1][j]+(a[i]==j);
for(int i=1; i<=n; ++i) if(fr[i]<=en[i]) tot[fr[i]][en[i]]++;
for(int i=2; i<=n; ++i) {
for(int j=1; j+i-1<=n; ++j) {
int L=j,R=j+i-1;
tot[L][R]=tot[L][R]+tot[L+1][R]+tot[L][R-1]-tot[L+1][R-1];
}
}
for(int i=1; i<=n; ++i) {
for(int j=1; j+i-1<=n; ++j) {
int L=j,R=i+j-1;
f[L][R]=max(val(L,R,0)+tot[L+1][R]-f[L+1][R],tot[L][R-1]-f[L][R-1]+val(L,R,1));
}
}
cout<<f[1][n]<<":"<<tot[1][n]-f[1][n];
return 0;
}
标签:le,return,int,题解,2024,P9911,Kuglice
From: https://www.cnblogs.com/djh0314/p/17984705