[dp] P2135 方块消除
posted on 2024-07-03 06:09:52 | under | source
挺好一道区间 dp。题解区写的都啥啊,根本看不懂。
首先假如相邻颜色段颜色相等,我们就将其合并,记颜色为 \(a_i\),数量为 \(b_i\)。可以证明,我们一定不会把一个颜色段拆开来操作,因为价值是平方,有 \((x+y)^2\ge x^2+y^2\)。
容易想到定义 \(g_{i,j}\) 表示消除 \([i,j]\) 内的所有颜色段的最大价值。转移就是枚举段内颜色,将所有该颜色的单独拎出来最后一起操作,然后价值就是其余段的 \(g\) 之和以及该颜色数量的平方。
但这是错误的!因为不一定要把所有该颜色的都放在一起最后消掉,我们可以选取一部分让它先被消掉以满足某些需求。
例如:
5
1 2 1 2 1
4 6 1 6 4
可以先消中间那段 1,使得两段 2 合并,最后合并两端的 1。这样更优。
如何解决?不妨将所有选取方案(即选择放在最后消掉的元素)分为两类:\(r\) 被选和不被选。假如 \(r\) 不被选,那么正常进行区间合并即可枚举到所有情况。假如 \(r\) 被选,必须记录当前被选元素的总数(\(\sum b\))。
\(r\) 是区间右端点。不妨记 \(f_{i,j,k}\) 为 \([i,j]\) 中,选取元素颜色为 \(a_j\) 且 \(j\) 一定被选取,选取元素数量之和为 \(k\) 时,的最大价值(注意先不计算选取元素的价值)。那么选 \(r\) 方案最大值就是 \(\max\limits_k f_{i,j,k}+k^2\to g_{i,j}\)。
转移很 simple,枚举 \([i,j-1]\) 中 \(a_p=a_j\) 的 \(p\),再枚举 \(k\),那么:\(f_{i,p,k}+g_{p+1,j-1}\to f_{i,j,k+b_j}\)。
记 \(m=\sum b\),复杂度 \(O(n^3m)\),瓶颈在 \(f\) 转移上。注意卡好枚举上下界,轻松跑过。
代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 55, C = 1e3 + 5;
int _n, n, a[N], b[N], f[N][N][C], g[N][N], sm[N][N];
signed main(){
memset(f, -1, sizeof f); //不要出现非法情况
cin >> _n;
for(int i = 1; i <= _n; ++i) scanf("%lld", &a[i]);
for(int i = 1; i <= _n; ++i) scanf("%lld", &b[i]);
for(int i = 1; i <= _n; ++i) //去重
if(a[i] == a[n]) b[n] += b[i];
else a[++n] = a[i], b[n] = b[i];
for(int i = 1; i <= n; ++i){
g[i][i] = b[i] * b[i], f[i][i][b[i]] = 0;
for(int j = 1; j <= _n; ++j) sm[i][j] = sm[i - 1][j] + (a[i] == j ? b[i] : 0); //下面转移的循环上界
}
for(int len = 2; len <= n; ++len)
for(int i = 1; i + len - 1 <= n; ++i){
int j = i + len - 1;
f[i][j][b[j]] = g[i][j - 1]; //假如只有j被选取
for(int k = i; k < j; ++k){
g[i][j] = max(g[i][j], g[i][k] + g[k + 1][j]);
if(a[k] == a[j])
for(int p = b[k]; p <= sm[k][a[k]] - sm[i - 1][a[k]]; ++p)
if(f[i][k][p] != -1)
f[i][j][p + b[j]] = max(f[i][j][p + b[j]], f[i][k][p] + g[k + 1][j - 1]);
}
for(int p = b[j]; p <= sm[j][a[j]] - sm[i - 1][a[j]]; ++p)
if(f[i][j][p] != -1) g[i][j] = max(g[i][j], f[i][j][p] + p * p);
}
cout << g[1][n];
return 0;
}
/*
5
1 2 1 2 1
4 6 1 6 4
209
*/

浙公网安备 33010602011771号