sol of P8866 [NOIP2022] 喵了个喵

披着构造外衣的大模拟。

本来想练习一下构造题,30 分钟糊出来了一个构造方案,以为做完了,没想到只是痛苦写代码和调试过程的开始。。。还好考场上没有想出来怎么构造,不然怕一等奖都拿不到

猜想有一个很强的性质:可以实现在一个局面中,每种牌至多只有一张。也就是说,如果一张牌在序列中是这种牌的第偶数次出现,那么它一定是用来消除局面中之前加入的牌的。

k=2n2 时显然可以随便做。在这个做法的基础上分析当加入一张牌时,局面中总共有 2n1 张牌怎么办,即可推导出构造过程。

构造过程的伪代码如下。

When dealing with the i-th card:

  • If the mode is normal:
    • If the card is to add and there will be 2n1 kinds of cards, switch the mode into alert.
    • Otherwise, move as normal.
  • If the mode is alert:
    • If there is a stack that the card on its top won't be removed before removing the i-th card or removing the card at its bottom, put the i-th card on its top. Then keep moving as normal (because there is only k3 kinds of cards and n1 stacks). After that, switch the mode to normal.
    • Otherwise, put the i-th card into the empty stack, switch the mode to easy, record the card at bottom which is the first to remove.
  • If the mode is easy:
    • If the i-th card is to remove a card in the bottom, do it and switch the mode to normal.
    • Move as normal but make sure that the stack with the first card in the bottom to be removed will be operate at most once.

大概调试了六个小时的样子(?),得出了最终代码(里面还有很多写法是为了调试方便)

#include<bits/stdc++.h>
using namespace std;
constexpr int N=605,M=2e6+5;
int n,m,K,a[M],pos[N],nxt[M],cnt,mb[N],mt[N],mode,te;
bool ise[N],isu[N];
vector<pair<int,int>>op;
set<int>st,sb;queue<int>qe,qu;
/*
void debug(){
	int xcnt=0;
	for(int j=1;j<=n;j++){
		printf("mb[%d]=%d,mt[%d]=%d,ise[%d]=%d\n",j,mb[j],j,mt[j],j,ise[j]);
		xcnt+=(!!mb[j])+(!!mt[j]);
	}
	assert(xcnt==cnt||(cnt==n*2-1&&xcnt==cnt-1));
}
*/
void move(int i){
	//printf("MOVE: cnt=%d,i=%d,te=%d,mode=%d\n",cnt,i,te,mode);
	//debug()
	if(sb.size()&&i==*sb.begin())sb.erase(sb.begin());
	if(nxt[i]){
		while(qe.size()&&!ise[qe.front()])qe.pop();
		//if(qe.empty())debug();
		//assert(qe.size());
		int k=qe.front();
		op.emplace_back(k,0);// STACK k has been changed!
		cnt++;
		if(mb[k]){// put on the top
			ise[k]=0;
			mt[k]=nxt[i];
			pos[a[i]]=k;
			st.insert(mt[k]);
			if(mt[k]>mb[k]){
				qu.push(k);isu[k]=1;
			}
		}else{// put on the bottom
			sb.insert(mb[k]=nxt[i]);
			pos[a[i]]=k;
		}
	}else{
		cnt--;
		if(mb[pos[a[i]]]==i){
			int k=pos[a[i]];
			if(mt[k]){
				op.emplace_back(te,0);
				op.emplace_back(k,te);// STACK k has been changed!
				if(mt[k]>mb[k])isu[k]=0;
				st.erase(mt[k]);
				sb.erase(mb[k]);
				sb.insert(mb[k]=mt[k]);
				mt[k]=0;
				if(k!=mode){
					ise[k]=1;
					qe.push(k);
				}
			}else{
				op.emplace_back(k,0);
				sb.erase(mb[k]);
				mb[k]=0;
			}
		}else{
			int k=pos[a[i]];
			op.emplace_back(k,0);// STACK k has been changed!
			if(mt[k]>mb[k])isu[k]=0;
			st.erase(mt[k]);
			mt[k]=0;
			if(k!=mode){
				ise[k]=1;
				qe.push(k);
			}
		}
	}
}
void work(int&i){
	//printf("WORK %d\n",i);
	int k=0;
	while(qu.size()&&!isu[qu.front()])qu.pop();
	if(qu.size())k=qu.front();else{
		auto p=st.upper_bound(nxt[i]);
		if(p!=st.end())k=pos[a[*p]];
	}
	if(!k){
		op.emplace_back(te,0);
		qe.push(te);// STACK te has been changed!
		ise[te]=1;sb.insert(mb[te]=nxt[i]);
		//printf("sb.insert %d\n",mb[te]);
		cnt++;pos[a[i]]=te;te=0;
		ise[mode=pos[a[*sb.begin()]]]=0;// MODE is WRONG!
		//printf("when i=%d, k=0, mode=%d, *sb.begin()=%d\n",i,mode,*sb.begin());
		//debug();
		return;
	}
	int p=nxt[i],ed=min(p,mb[k]);
	op.emplace_back(k,0);cnt++;// STACK k has been changed!
	for(i++;i<ed;i++)move(i);
	if(ed==mb[k]){
		//puts("point 1");
		isu[k]=0;
		st.erase(mt[k]);
		sb.erase(mb[k]);
		sb.insert(mb[k]=mt[k]);
		st.insert(mt[k]=p);
		pos[a[mt[k]]]=k;
		pos[a[mb[k]]]=k;
		if(mt[k]>mb[k])isu[k]=1;
		op.emplace_back(te,0);
		op.emplace_back(k,te);// STACK k has been changed!
		cnt--;
	}else{
		//puts("point 2");
		op.emplace_back(k,0);
		cnt--;
	}
}
int main(){
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	int T;cin>>T;while(T--){
		op.clear();st.clear();
		memset(mb,0,sizeof(mb));
		memset(mt,0,sizeof(mt));
		memset(isu,0,sizeof(isu));
		sb.clear();
		while(qe.size())qe.pop();
		while(qu.size())qu.pop();
		cin>>n>>m>>K;te=n;
		for(int i=1;i<n;i++){
			qe.push(i);
			ise[i]=1;
		}
		ise[n]=0;
		memset(pos,0,sizeof(pos));
		for(int i=1;i<=m;i++){
			nxt[i]=0;
			cin>>a[i];
			if(pos[a[i]]){
				nxt[pos[a[i]]]=i;
				pos[a[i]]=0;
			}else pos[a[i]]=i;
		}
		mode=0;cnt=0;
		for(int i=1;i<=m;i++){
			if(!mode){
				if(nxt[i]&&cnt==n*2-2)work(i);
				else move(i);
			}else{
				if(!nxt[i]&&mb[pos[a[i]]]==i){
					int k=pos[a[i]];
					//assert(mode==k);
					op.emplace_back(k,0);// STACK k has been changed!
					te=k;mode=0;cnt--;ise[te]=0;
					mt[k]=mb[k]=0;sb.erase(sb.begin());
	//printf("SWITCH: cnt=%d,i=%d,te=%d\n",cnt,i,te);
	//debug();
				}else move(i);
			}
		}
		printf("%lu\n",op.size());
		for(auto p:op){
			if(p.second)printf("2 %d %d\n",p.first,p.second);
			else printf("1 %d\n",p.first);
		}
	}
	return 0;
}
posted @   hihihi198  阅读(187)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示
主题色彩