CF1312E Array Shrinking 区间dp
Posted badcw
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF1312E Array Shrinking 区间dp相关的知识,希望对你有一定的参考价值。
给定一个长度为 (n) 的序列 (a),(1 le n le 500, 1 le a_i le 1000)
类似 2048 的玩法,每次可以将相邻的两个一样的数字 x 合并为 x + 1,求最后整个序列的最小长度为多少
一个比较显然的结论是本题的数据范围和做法是区间 dp,因为涉及到区间的合并问题
然后会发现直接做区间 dp 的话会很不好写,因为比较显然的结论是一个区间并不能由两个小区间去决定它的答案,可能是由很多个小区间才能合并组成,当区间的答案为 1 时才会去考虑合并还要考虑数字是多少
令 (f_{i,j}) 表示 (i o f_{i,j}-1) 这一段可以组成一个数 (j),(f_{i,j}=0) 表示从 (i) 为起点不能构成 (j) 这个数
在 (O(ncdot max(a_i))) 的复杂度内就可以解决这个问题
- 首先 (a_i=j) 时显然有 (f_{i,j}=i+1)
- (f_{i,j}=f_{f[i][j-1],j-1}) 就是往后枚举两个 (j-1),注意要第一维枚举 (j) 顺序问题
然后 (dp_{i,j}) 表示这个区间内至少需要多少个数表示,首先置为 (inf),对于 (f_{i,j}) 存在的点,则把 (dp_{i,f[i][j] - 1}) 置为 1 表示这个区间只需要一个数表示,然后做第一维枚举区间长度的区间 (dp) 即可,(dp_{1,n}) 就是答案
/*================================================================
*
* 创 建 者: badcw
* 创建日期: 2020/3/9
*
================================================================*/
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 505;
const int maxm = 2005;
const int mod = 1e9+7;
ll qp(ll a, ll n) {
ll res = 1;
while (n > 0) {
if (n & 1) res = res * a % mod;
a = a * a % mod;
n >>= 1;
}
return res;
}
template <class T>
inline bool scan(T& ret) {
char c;
int sgn;
if (c = getchar(), c == EOF) return 0; // EOF
while (c != '-' && (c < '0' || c > '9')) c = getchar();
sgn = (c == '-') ? -1 : 1;
ret = (c == '-') ? 0 : (c - '0');
while (c = getchar(), c >= '0' && c <= '9') ret = ret * 10 + (c - '0');
ret *= sgn;
return 1;
}
//template <class T>
//inline void out(T x) {
// if (x > 9) out(x / 10);
// putchar(x % 10 + '0');
//}
int n;
int a[maxn];
int f[maxn][maxm];
int dp[maxn][maxn];
int main(int argc, char* argv[]) {
scanf("%d", &n);
memset(dp, 0x3f, sizeof dp);
for (int i = 1; i <= n; i++) scanf("%d", &a[i]), dp[i][i] = 1;
for (int j = 1; j < maxm; j++) {
for (int i = 1; i <= n; i++) {
if (a[i] == j) f[i][j] = i + 1;
else f[i][j] = f[f[i][j - 1]][j - 1];
if (f[i][j]) dp[i][f[i][j] - 1] = 1;
}
}
for (int len = 1; len <= n - 1; ++len) {
for (int i = 1; i + len <= n; ++i) {
int j = i + len;
for (int k = i; k < j; ++k) {
dp[i][j] = min(dp[i][j], dp[i][k] + dp[k + 1][j]);
}
}
}
int res = min(n, dp[1][n]);
printf("%d
", res);
return 0;
}
以上是关于CF1312E Array Shrinking 区间dp的主要内容,如果未能解决你的问题,请参考以下文章
Codeforces 1312E. Array Shrinking
Educational Codeforces Round 83 (Rated for Div. 2) E. Array Shrinking 区间DP