洛谷 P5154 数列游戏
Description
Solution
明显的区间dp
根据套路,设计状态:
f[i][j]f[i][j] 表示,删去区间 [i,j] 之间的数,能得到的最大得分。
但是我们发现,这个并不好转移,我们无法记录是否都能被删除。
所以我们转换一下思路。
设 f[i][j] 表示,区间 [i,j] 能否被完全删除。
那么我们有两种可能:
-
a[i] 和 a[j] 不互质,那么我们可以从 f[i+1][j−1] 转移过来。
-
枚举断点 k,我们先令区间 [i,k] 和 区间 [k+1,j] 合并,在合并区间 [i,j]
有了判断能否删除的状态之后,我们还要统计答案。
所以设 g[i] 为处理前 i 个数之后能得到的最大得分。
那么转移方程就是:g[i]=max(g[i],g[j−1]+sum[i]−sum[j−1])
g[i] 初值为 g[i−1],sum[i] 为前 i 个数的分数前缀和。
Code
#include <iostream>
#include <cstdio>
#include <algorithm>
#define ll long long
using namespace std;
const ll N = 1010;
ll n;
ll a[N], b[N], f[N][N], g[N];
ll sum[N];
inline ll gcd(ll a, ll b){
return !b ? a : gcd(b, a % b);
}
signed main(){
scanf("%lld", &n);
for(ll i = 1; i <= n; i++)
scanf("%lld", &a[i]);
for(ll i = 1; i <= n; i++){
scanf("%lld", &b[i]);
sum[i] = sum[i - 1] + b[i];
}
for(ll i = 1; i < n; i++)
f[i][i + 1] = (gcd(a[i], a[i + 1]) != 1);//f 数组初值
for(ll len = 3; len <= n; len++)
for(ll i = 1; i + len - 1 <= n; i++){
ll j = i + len - 1;
if(len > 3 && gcd(a[i], a[j]) != 1) f[i][j] |= f[i + 1][j - 1];//转移 1
for(ll k = i + 1; k < j - 1; k++)
f[i][j] |= (f[i][k] & f[k + 1][j]);//转移 2
}
for(ll i = 1; i <= n; i++){
g[i] = g[i - 1];
for(ll j = 1; j <= i; j++)
if(f[j][i])
g[i] = max(g[i], g[j - 1] + sum[i] - sum[j - 1]);
}
printf("%lld\n", g[n]);
return 0;
}
End
本文作者:xixike
本文链接:https://www.cnblogs.com/xixike/p/15363382.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步