【题解】NOIP2022 喵了个喵

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

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

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

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

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

否则我们记第一个出现在栈底的牌记为 yy 所在栈上面的牌为 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();}

作者:7KByte

出处:https://www.cnblogs.com/7KByte/p/16930110.html

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   7KByte  阅读(1214)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
历史上的今天:
2021-11-27 【游记】NOIP2021
more_horiz
keyboard_arrow_up dark_mode palette
选择主题
点击右上角即可分享
微信分享提示