Loading

【题解】NOIP2022 喵了个喵

个人感觉难度不如移球游戏。

首先对于 \(k=2n-2\) 的情况,我们用前面 \(n-1\) 栈,保持每个栈大小不超过 \(2\),这样每加入一张新牌,如果在前 \(n-1\) 个栈里出现了,就可以通过第 \(n\) 个栈消掉,\(n\) 号栈记为特殊栈。

对于 \(k = 2n-1\) 的情况。这是会多出来一种情况,就是前面 \(n-1\) 个栈填满了 \(2n-2\) 个不同的牌。现在又来了一张新牌,如果直接放第 \(n\) 个栈会影响后面的消去。

不妨记 \(x\) 为这张新牌。那么我们讨论将这个 \(x\) 放到哪。那么现在我们只关心 \(x\) 到下一个 \(x\) 之间的牌,显然这些牌不包含 \(x\),且全部在前 \(n-1\) 个栈内出现恰好一次。

如果这些牌全部在栈顶,则将 \(x\) 放到特殊栈(在代码中为 type 1)。

否则我们记第一个出现在栈底的牌记为 \(y\)\(y\) 所在栈上面的牌为 \(z\)

如果 \(z\) 出现了偶数次,那么就把 \(x\) 放在 \(z\) 上面,\(z\) 放到特殊栈,最后通过 \(2\) 操作把 \(x\) 消掉(代码中为 type 3)。

否则我们把 \(x\) 放到特殊栈,最后一定能把 \(y,z\) 都消掉,然后把 \(y,z\) 所在的栈记为新的特殊栈(代码中为 type 2)。

这样我们通过简单讨论解决了这道题。我认为这题唯一的难点在于想到特殊栈会移动。其余的对于省一选手应该都是基操。

#define N 605
#define M 2000005
int n, m, kk, res, id;
int a[M], c[N], u[N], up[N], dn[N], p[N];
struct node{int op, x, y;};
queue<int>q; vector<node>ans;
void clear(){
	memset(c, 0, sizeof(c));
	memset(u, 0, sizeof(u));
	memset(up, 0, sizeof(up));
	memset(dn, 0, sizeof(dn));
	memset(p, 0, sizeof(p));
	while(!q.empty())q.pop();
	id = n, res = 2 * (n - 1);
	rp(i, n - 1)q.push(i), q.push(i);
	ans.clear();
}
void ed(int x){ans.pb(node{1, x, 0});}
void ed(int x,int y){ans.pb(node{2, x, y}); }
void match(int w){
	//assert(c[w]);
	
	int ps = c[w];
	if(u[w] == 1){
		ed(id), ed(ps, id);
		if(p[ps] == 2)u[up[ps]]--, dn[ps] = up[ps];
		p[ps] --, c[w] = 0, q.push(ps);
	}
	else{
		ed(ps), c[w] = 0, p[ps] --, q.push(ps);
	}
	res ++;
}
void ins(int x){
	while(!q.empty() && (p[q.front()] == 2 || q.front() == id))q.pop();
	
	int y = q.front(); q.pop();
	if(p[y] == 0)dn[y] = x, c[x] = y, u[x] = 1;
	else up[y] = x, c[x] = y, u[x] = 2;
	ed(y), p[y] ++, res --;
}

int calc(int s){
	int t = s + 1;
	while(a[t] != a[s] && u[a[t]] == 2)t++;
	if(a[t] == a[s]){ //type 1
		ed(id);
		rep(i, s + 1, t - 1)
			if(c[a[i]])match(a[i]); else ins(a[i]);
		ed(id);
	}
	else{
		int y = c[a[t]], k = up[y], op = 0;
		rep(i, s + 1, t - 1)if(a[i] == k)op ^= 1;
		if(op){      //type 2
			ed(id);
			rep(i, s + 1, t - 1){
				if(a[i] == k)ed(y);
				else if(c[a[i]])match(a[i]);
				else ins(a[i]);
			}
			ed(y);
			c[k] = 0, c[a[t]] = 0, 
			c[a[s]] = id, dn[id] = a[s], u[a[s]] = 1, p[id] = 1;
			res += 1, q.push(id), id = y, p[y] = 0; 
		}
		else{       //type 3
			ed(y);
			rep(i, s + 1, t - 1){
				if(a[i] == k)ed(id);
				else if(c[a[i]])match(a[i]);
				else ins(a[i]);
			}
			ed(id), ed(id, y);
			c[a[t]] = 0, u[k] = 1, dn[y] = k, up[y] = a[s];
			c[a[s]] = y, u[a[s]] = 2;
		}
	}return t;
}
void solve(){
	read(n, m, kk), clear();
	rp(i, m)read(a[i]);
	for(int i = 1; i <= m; i ++){
		if(c[a[i]])match(a[i]);
		else{
			if(res)ins(a[i]);
			else i = calc(i);
		}
	}
	printf("%d\n", si(ans));
	go(x, ans){
		if(1 == x.op)printf("1 %d\n", x.x);
		else printf("2 %d %d\n", x.x, x.y);
	}
}

int main() {int T; read(T); while(T--)solve();}
posted @ 2022-11-27 17:09  7KByte  阅读(1183)  评论(0编辑  收藏  举报