题解:P10395 青蛙寻青。
题意
link
Subtask 1
写一个爆搜,一个颜色可以跟上一个相同,也可以是接在上一个颜色后面新开一个颜色,最后递归出口要判每个颜色是或否全部出现。
Subtask 2
显然有一个
f[i][j] = min(f[i-1][j], f[i-1][j-1]) + (b[i] != c[j]);
Subtask 3
上面那个 dp 看起来没有前途,所以尝试以颜色划分阶段。
首先对相同颜色的段“缩点”,最后目标状态的
然后
然后问题转化为三维偏序问题,复杂度
Subtask 4
考虑在上面 dp 的基础上优化,首先我们按照颜色转移,可以确定
Code
// Problem: P10395
#include <bits/stdc++.h>
#define db double
#define ll long long
#define pc putchar
#define gc getchar
#define sz(x) ((int)x.size())
#define F(i, a, b) for (int i = (a); i <= (b); ++i)
#define D(i, a, b) for (int i = (a); i >= (b); --i)
#define TM cout<<fabs(&Med-&Mbe)/1048576.0<<"MB "<<1.0*clock()/CLOCKS_PER_SEC*1000<<"ms\n"
bool Mbe;
using namespace std;
namespace IO {
#define typ ll
inline typ rd() {
typ x = 0; bool f = 1; char ch = gc();
while (ch < '0' || ch > '9') { if (ch == '-') f = 0; ch = gc(); }
while (ch >= '0' && ch <= '9') x = (x << 1) + (x << 3) + (ch ^ 48), ch = gc();
return (f ? x : (-x));
}
inline void wr(typ x) {
if (x < 0) pc('-'), x = -x;
if (x > 9) wr(x / 10); pc(x % 10 + '0');
}
}
using namespace IO;
// ----------------- Main Code -----------------
const int N = 2e6 + 5;
int n, m, a[N], c[N], id[N], k;
vector<int> G[N];
void upd(int p, int x) { ++p; for (int i = p; i <= m + 1; i += (i & -i)) c[i] = min(c[i], x); }
int qry(int p) { ++p; int res = 1e9; for (int i = p; i; i -= (i & -i)) res = min(res, c[i]); return res; }
int main() {
n = rd(), m = rd();
F(i, 1, n) {
a[i] = rd();
if (!id[a[i]]) id[a[i]] = ++k;
else if (a[i] != a[i-1]) { wr(-1), pc('\n'); return 0; }
}
if (m < k) { wr(-1), pc('\n'); return 0; }
F(i, 1, m) {
int x = rd();
G[id[x]].push_back(i);
}
memset(c, 0x3f, sizeof c);
int ans = m;
upd(0, 0);
F(i, 1, k) {
for (int v : G[i]) if (v >= i && m-v >= k-i) {
int p = v - i; // 缩点后的编号
int f_v = qry(p) + v - 1; // 树状数组中存的值是 f_i - i
ans = min(ans, f_v + m - v);
upd(p, f_v - v);
}
}
wr(ans), pc('\n');
return 0;
}