AT_arc195_d [ARC195D] Swap and Erase 题解
我们可以把操作过程分成两个阶段,毕竟先进行全部的交换操作,再进行所有的删除操作,对比一边换一遍删是不会更劣的。
接下来还需要注意到一个结论,一个数至多被交换一次。我们考虑一次交换带来的影响,设相邻的两个数 \(x,y\) 交换后最多可以减少两次操作,即 \(x, y, x, y\) 我们交换中间两个数的情况,那么我们有 \(1\) 的正收益。考虑交换两次是什么样子,我们把 \(x, y, z\) 变成了 \(y, z, x\),最好情况下的排列是 \(y, x, y, z, x\),我们操作了两次但也只减少了两次操作,所以也是不优的,大于两次的也很容易这么贪心的证出来。
基于这个事实,考虑有 \(dp_{i,0/1}\) 表示清空前 \(i\) 位,且第 \(a_i, a_{i-1}\) 位不进行/进行交换的最小操作次数。转移讨论:
设命题 \(P = a_i \ne a_{i - 1}, Q = a_i \neq a_{i - 2}, R = a_i \ne a_{i - 3}\)。
- 当不交换时,讨论前一位的交换情况。
- 当交换时,基于上面的分析第 \(i - 1\) 位不能再做交换,那么考虑讨论 \(i - 2\) 的交换。
直接转移即可做到 \(O(n)\)。代码。
Ex
维护一个序列,每次可以区间加、区间赋值,询问把任意一个区间变成空数列的最小操作次数。\(n, m \le 10^5\)。
考虑上面的 dp 实质上在做 \(\min +\) 卷积,考虑 ddp,我们把转移放到矩阵上。
那考虑操作分别的意义:
- 区间加
注意到区间内部的数并不会因为区间加而改变大小关系,只有 \([l, l + 2], [r + 1, r + 3]\) 的会变动,只需要暴力维护这些位置即可,注意到上述的命题 \(P, Q, R\) 都会随着 \(a\) 改变,所以还需要维护一棵支持区间加、区间推平、单点查的线段树。
- 区间推平
边界依然按照刚才的方法暴力,注意到推平后 \(P = Q = R = 0\),那么中间的矩阵形状是固定的,只需要预处理这样的矩阵的 \(k\) 次方直接 pushdown 即可。
- 询问
先算出 \(dp_{1,0/1}, dp_{2,0/1}\) 的值,然后乘上区间的矩阵即可。代码。
// ubsan: undefined
// accoders
// 如果命运对你缄默, 那就活给他看。
#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast", "inline", "-ffast-math")
#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
// #define int LL
const int maxn = 1e5 + 10;
const int INF = 0x3f3f3f3f;
int n, m, a[maxn];
inline int cmi(int& x, int y) {
if(y < x) x = y; return x;
}
struct mat {
int g[4][4];
inline void E () {
for(int i = 0; i < 4; ++ i)
for(int j = 0; j < 4; ++ j) g[i][j] = INF * (i != j);
}
mat () { memset(g, 0x3f, sizeof g); }
inline mat operator * (const mat& b) const {
mat c;
for(int i = 0; i < 4; ++ i)
for(int k = 0; k < 4; ++ k)
if(g[i][k] != INF)
for(int j = 0; j < 4; ++ j) c.g[i][j] = min(c.g[i][j], g[i][k] + b.g[k][j]);
return c;
}
inline bool operator == (const mat& b) const {
for(int i = 0; i < 4; ++ i)
for(int j = 0; j < 4; ++ j) if(g[i][j] != b.g[i][j]) return 0;
return 1;
}
inline void print() {
for(int i = 0; i < 4; ++ i, cout << '\n')
for(int j = 0; j < 4; ++ j) {
if(g[i][j] == INF) cout << -1 << ' ';
else cout << g[i][j] << ' ';
}
}
} ID;
inline bool operator != (const mat& a, const mat& b) { return !(a == b); }
inline mat make(int P, int Q, int R) {
mat a;
a.g[0][0] = P, a.g[0][1] = Q;
a.g[1][2] = P + Q + 1, a.g[1][3] = P + R + 1;
a.g[2][0] = a.g[3][1] = 0;
return a;
}
mat pw[maxn];
inline void init() {
pw[0].E(), ID.E();
mat e = make(0, 0, 0);
for(int i = 1; i <= n; ++ i) pw[i] = pw[i - 1] * e;
}
namespace sgt1 {
int as[maxn << 2], ad[maxn << 2];
inline void ev(int u, int ass, int add) {
if(ass) as[u] = ass, ad[u] = 0;
ad[u] += add;
}
inline void dw(int u) {
ev(u << 1, as[u], ad[u]);
ev(u << 1 | 1, as[u], ad[u]);
as[u] = 0, ad[u] = 0;
}
inline void modf(int u, int l, int r, int ql, int qr, int ass, int add) {
if(ql <= l && r <= qr) return ev(u, ass, add);
int mid = l + r >> 1; dw(u);
if(ql <= mid) modf(u << 1, l, mid, ql, qr, ass, add);
if(qr > mid) modf(u << 1 | 1, mid + 1, r, ql, qr, ass, add);
}
inline int Q(int u, int l, int r, int p) {
if(l == r) return as[u] + ad[u];
int mid = l + r >> 1; dw(u);
if(p <= mid) return Q(u << 1, l, mid, p);
else return Q(u << 1 | 1, mid + 1, r, p);
}
}
inline mat fpow(mat a, int b) {
mat c; c.E();
for(; b; b >>= 1, a = a * a)
if(b & 1) c = c * a;
return c;
}
namespace sgt2 {
mat g[maxn << 2];
mat as[maxn << 2];
inline void pu(int u) {
g[u] = g[u << 1 | 1] * g[u << 1 ];
}
inline void dw(int u, int l, int r) {
int mid = l + r >> 1;
if(as[u] != ID) {
as[u << 1] = g[u << 1] = pw[mid - l + 1];
as[u << 1 | 1] = g[u << 1 | 1] = pw[r - mid];
as[u].E();
}
}
inline void modf1(int u, int l, int r, int p, mat k) {
if(l == r) return g[u] = k, void();
int mid = l + r >> 1; dw(u, l, r);
if(p <= mid) modf1(u << 1, l, mid, p, k);
else modf1(u << 1 | 1, mid + 1, r, p, k);
pu(u);
}
inline void modf2(int u, int l, int r, int ql, int qr) {
// if(as[u] != ID) return ;
if(ql <= l && r <= qr) return as[u] = g[u] = pw[r - l + 1], void();
dw(u, l, r);
int mid = l + r >> 1;
if(ql <= mid) modf2(u << 1, l, mid, ql, qr);
if(qr > mid) modf2(u << 1 | 1, mid + 1, r, ql, qr);
pu(u);
}
inline mat Q(int u, int l, int r, int ql, int qr) {
if(ql <= l && r <= qr) return g[u];
int mid = l + r >> 1; dw(u, l, r);
if(qr <= mid) return Q(u << 1, l, mid, ql, qr);
if(ql > mid) return Q(u << 1 | 1, mid + 1, r, ql, qr);
return Q(u << 1 | 1, mid + 1, r, ql, qr) * Q(u << 1, l, mid, ql, qr);
}
inline void build(int u, int l, int r) {
as[u].E(), g[u].E();
if(l == r) return ;
int mid = l + r >> 1;
build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r), pu(u);
}
}
inline void maintain(int l, int r) {
for(int i = l - 3; i <= min(n, l + 2); ++ i) {
if(i >= 1) a[i] = sgt1::Q(1, 1, n ,i);
if((i - 3 >= 0) && i >= l) {
int P = a[i] != a[i - 1];
int Q = a[i] != a[i - 2];
int R = a[i] != a[i - 3];
sgt2::modf1(1, 1, n, i, make(P, Q, R));
}
}
for(int i = r - 2; i <= min(r + 3, n); ++ i) {
if(i >= 1) a[i] = sgt1::Q(1, 1, n, i);
if((i - 3 >= 0) && (i > r)) {
int P = a[i] != a[i - 1];
int Q = a[i] != a[i - 2];
int R = a[i] != a[i - 3];
sgt2::modf1(1, 1, n, i, make(P, Q, R));
}
}
}
inline void solve0(int l, int r, int x) {
sgt1::modf(1, 1, n, l, r, 0, x);
maintain(l, r);
}
inline void solve1(int l, int r, int x) {
sgt1::modf(1, 1, n, l, r, x, 0);
maintain(l, r);
if(l + 3 <= r) sgt2::modf2(1, 1, n, l + 3, r);
}
inline int Q(int l, int r) {
if(l == r) return 1;
auto debug = ID;
a[l] = sgt1::Q(1, 1, n, l), a[l + 1] = sgt1::Q(1, 1, n, l + 1);
mat ans;
// al, al+1
ans.g[0][0] = 1 + (a[l] != a[l + 1]);
ans.g[1][0] = ans.g[0][0] + 1;
ans.g[2][0] = 1;
ans.g[3][0] = INF;
if(l + 2 <= r) {
auto G = sgt2::Q(1, 1, n, l + 2, r);
ans = G * ans;
}
return min(ans.g[0][0], ans.g[1][0]);
}
signed main() {
freopen("swap.in", "r", stdin);
freopen("swap.out", "w", stdout);
ios :: sync_with_stdio(false);
cin.tie(0), cout.tie(0);
cin >> n >> m;
init();
sgt2::build(1, 1, n);
for(int i = 1; i <= n; ++ i) {
cin >> a[i];
sgt1::modf(1, 1, n, i, i, a[i], 0);
if(i >= 3) sgt2::modf1(1, 1, n, i, make(a[i] != a[i - 1], a[i] != a[i - 2], a[i] != a[i - 3]));
}
for(int i = 1; i <= m; ++ i) {
int op, l, r, x;
cin >> op >> l >> r;
if(op == 1) {
cin >> x;
solve0(l, r, x);
} else if (op == 2) {
cin >> x, solve1(l, r, x);
} else {
cout << Q(l, r) << '\n';
}
}
return 0;
}

浙公网安备 33010602011771号