[NOIP2022] 喵了个喵 题解
[NOIP2022] 喵了个喵 题解
先考虑\(k=2n-2\),这个数字提示我们每个栈放两种颜色,剩下一个栈辅助操作。那么颜色被分为两类
- 在栈底,可以通过操作2消去。
- 在栈顶,可以通过操作1消去。
这样就做完了。
现在普通栈放满了,又来了一个颜色,容易想到,如果这个颜色到下一个颜色之间没有栈底颜色,那么实际上可以直接把这个颜色放在辅助栈里面消去。这是第一种情况。
接下来让我们考虑这个颜色到下一个颜色之间有栈底颜色的情况,按照一些基本套路,可以考虑第一个栈底颜色,那么中间这些颜色可以分为可以按第一种情况操作的和\(z\)。
令新的颜色为\(x\),第一个栈底颜色为\(y\),对应的栈顶颜色为\(z\)。
我们先来思考\(x\)和\(y\)中间这些颜色怎么放,其实只用考虑怎么放\(z\),因为剩下这些颜色可以直接用操作1干掉。
- \(z\)出现奇数次,直接把\(x\)放在辅助栈,\(z\)放在\(y\)栈,那么在中间这些颜色放完后\(z\)就没有了,那么接下来可以把\(y\)也通过操作1消去。这时候\(y\)原本在的这个栈就空出来了,那么可以把它变成新的辅助栈。
- \(z\)出现偶数次,这个时候我们就没办法把\(y\)上面变成空的了。所以只能通过操作2消去\(y\),所以辅助栈一定要空出来,注意到其实可以直接把\(x\)放在\(y\)所在的栈的栈顶,同时把\(z\)放在辅助栈,这样在辅助栈中的\(z\)一定会被消去。最后就可以通过操作2把\(y\)消掉,这时候辅助栈就又空出来了。
直接模拟上面几种情况,就可以构造出\(k=2n-1\)的合法方案了。
改完题发现这题并没有想象中这么难,想法还是比较自然的。可能是这类构造做的不多,导致比赛时慌了。
#include <cstdio>
#include <iostream>
#include <vector>
#include <queue>
#include <cstring>
#define LL long long
using namespace std;namespace io {
const int SIZE = (1 << 21) + 1;
char ibuf[SIZE], *iS, *iT, obuf[SIZE], *oS = obuf, *oT = oS + SIZE - 1, c, qu[55]; int f, qr;
#define gc() (iS == iT ? (iT = (iS = ibuf) + fread (ibuf, 1, SIZE, stdin), (iS == iT ? EOF : *iS ++)) : *iS ++)
inline void flush () {
fwrite (obuf, 1, oS - obuf, stdout);
oS = obuf;
}
inline void putcc (char x) {
*oS ++ = x;
if (oS == oT) flush ();
}
template <class I>
inline void gi (I &x) {
for (f = 1, c = gc(); c < '0' || c > '9'; c = gc()) if (c == '-') f = -1;
for (x = 0; c <= '9' && c >= '0'; c = gc()) x = x * 10 + (c & 15); x *= f;
}
template <class I>
inline void print (I x) {
if (!x) putcc ('0'); if (x < 0) putcc ('-'), x = -x;
while (x) qu[++ qr] = x % 10 + '0', x /= 10;
while (qr) putcc (qu[qr --]);
}
}
using namespace io;
const int N = 610;
const int S = 2e6 + 10;
int n, m, k, a[S], tot;
struct Move {
int tp, x, y;
Move(int TP, int X, int Y) : tp(TP), x(X), y(Y) {}
};
vector<Move> ans;
inline void move(int x) {ans.emplace_back(Move(1, x, 0));}
inline void move(int x, int y) {ans.emplace_back(Move(2, x, y));}
queue<int> nor;
int sz[N], type[N];
int id, ins[N], top[N];
void insert(int x) {
while(!nor.empty() && (sz[nor.front()] == 2 || nor.front() == id))
nor.pop();
int p = nor.front();
if(sz[p] == 0) type[x] = 1;
else type[x] = 2, top[p] = x;
ins[x] = p, ++sz[p], move(p), ++tot;
}
void match(int x) {
nor.push(ins[x]);
if(type[x] == 1) {
move(id), move(id, ins[x]);
--sz[ins[x]], type[top[ins[x]]] = 1, top[ins[x]] = 0;
}
else if(type[x] == 2){
move(ins[x]);
--sz[ins[x]], top[ins[x]] = 0;
}
ins[x] = type[x] = 0;
--tot;
}
int work(int l) {
int r = l + 1;
while(a[r] != a[l] && type[a[r]] == 2 && r <= m) ++r;
if(a[r] == a[l]) {
move(id);
for(int i = l + 1; i < r; ++i) {
if(ins[a[i]]) match(a[i]);
else insert(a[i]);
}
move(id);
}
else {
int parity = 0, y = a[r], st = ins[a[r]], z = top[st], x = a[l];
for(int i = l + 1; i < r; ++i) parity ^= (a[i] == z);
if(parity) {
move(id);
for(int i = l + 1; i < r; ++i) {
if(a[i] == z) move(st);
else if(ins[a[i]]) match(a[i]);
else insert(a[i]);
}
move(st);
type[x] = 1, sz[id] = 1, ins[x] = id;
type[y] = type[z] = 0, top[st] = 0, ins[y] = ins[z] = 0, sz[st] = 0;
nor.push(id);
--tot, id = st;
}
else {
move(st);
for(int i = l + 1; i < r; ++i) {
if(a[i] == z) move(st);
else if(ins[a[i]]) match(a[i]);
else insert(a[i]);
}
move(id), move(id, st);
top[st] = x;
type[z] = 1, type[x] = 2, ins[x] = st;
type[y] = 0, ins[y] = 0;
}
}
return r;
}
void clear() {
ans.clear();
memset(ins, 0, sizeof ins);
memset(top, 0, sizeof top);
memset(sz, 0, sizeof sz);
memset(type, 0, sizeof type);
while(!nor.empty()) nor.pop();
for(int i = 2; i <= n; ++i)
nor.push(i);
tot = 0, id = 1;
}
void out() {
print(ans.size()), putcc('\n');
for(auto x : ans) {
if(x.tp == 1)
putcc('1'), putcc(' '), print(x.x);
else
putcc('2'), putcc(' '), print(x.x), putcc(' '), print(x.y);
putcc('\n');
}
return ;
}
void solve() {
gi(n), gi(m), gi(k);
clear();
for(int i = 1; i <= m; ++i) gi(a[i]);
for(int i = 1; i <= m; ++i) {
if(ins[a[i]]) match(a[i]);
else if(tot < 2 * (n - 1)) insert(a[i]);
else i = work(i);
}
out();
}
int main() {
freopen("meow.in","r",stdin);
freopen("meow.out","w",stdout);
int T = 0; gi(T);
while(T--) solve();
flush();
}