[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();
}
posted @ 2022-12-11 11:29  DCH233  阅读(662)  评论(0编辑  收藏  举报