记录编号 |
581814 |
评测结果 |
AAAAAAAAAAAAAAAAAAAA |
题目名称 |
[NOIP 2022] 喵了个喵 |
最终得分 |
100 |
用户昵称 |
┭┮﹏┭┮ |
是否通过 |
通过 |
代码语言 |
C++ |
运行时间 |
5.768 s |
提交时间 |
2023-08-14 20:39:54 |
内存使用 |
10.88 MiB |
显示代码纯文本
#include <bits/stdc++.h>
using namespace std;
const int N = 310,M = 2e6+10;
int T,n,m,k;
int a[M],id[2*N];//a为原数组
//id为某种牌所在栈编号,没有则为0
struct made{
int v1,v2;
};
int stp;//辅助栈编号
deque<int>st[N];//每个栈
queue<int>q;//队列维护空栈
vector<made>ans;//答案
void first_() {
ans.clear();//清空答案
stp = n;//最开始辅助栈定为n
memset(id,0,sizeof(id));//初始化
}
void pu(int x,int y){
ans.push_back((made){x,y});
}//方便记答案
bool simple(int x){//普通相消
int stx = id[x];//x所在栈
if(!stx){//该x未在栈内
if(q.empty())return false;//所有栈都满了,开始特殊处理
id[x] = stx = q.front();//x入进队头的栈并记录
q.pop();
pu(stx,0);//入编号为stx的栈
st[stx].push_back(x);//入栈
}
else{
q.push(stx);//元素弹出,多了一个栈的位置
if(st[stx].back() == x){//栈顶相等
pu(stx,0);//直接入该栈相消
st[stx].pop_back();
}
else{//栈底相等
pu(stp,0);//首先放到辅助栈里
pu(stx,stp);//按照操作2相消
st[stx].pop_front();//栈底出栈
}
id[x] = 0;//更新id,消除掉则x未在栈内
}
return true;
}
int main(){
freopen("noip2022_meow.in","r",stdin);
freopen("noip2022_meow.out","w",stdout);
scanf("%d",&T);
while(T--){
scanf("%d%d%d",&n,&m,&k);//n个栈 m个卡牌 k种卡牌
first_();
for(int i = 1;i <= m;i++)
scanf("%d",&a[i]);//离线操作
while(!q.empty())q.pop();
for(int i = 1;i < n;i++){q.push(i);q.push(i);}
for(int i = 1;i <= m;i++){
if(!simple(a[i])){//当栈都满了以后
int now = a[i],nx = i+1;int x = a[nx];
for(;nx <= m && x != now && x == st[id[x]].back();nx++,x = a[nx]);
//找到now后第一个在栈底的元素
//此时nx是i后第一个不在栈顶上的下标,x是a[nx]
if(x == now){//X=P
pu(stp,0);//将p入到辅助栈内
for(int j = i+1;j < nx;j++)simple(a[j]);//中间正常
pu(stp,0);//最后再将p入到辅助栈内消掉,辅助栈不变
}
else{
int stx = id[x];//X所在栈
int y = st[stx].back();//X所在栈顶Y
bool flag = true;//判断奇偶数
for(int j = i+1;j < nx;j++)//栈顶Y出现次数
if(a[j] == y)flag = !flag;
if(flag){//偶数
pu(stx,0);//将P放到X所在栈
st[stx].push_back(a[i]);
for(int j = i+1;j < nx;j++){
if(a[j] == y)pu(stp,0);//将Y全部放到辅助栈内相消,辅助栈依旧为空
else simple(a[j]);//其他普通相消
}
pu(stp,0);pu(stx,stp);//最后把X放到辅助栈内用操作2相消
st[stx].pop_front();//栈底出栈
id[x] = 0;id[now] = stx;//更新,P的栈为X的栈,X被消掉了没有栈
//id[y] = 0;全部消掉了,本来就是0,变不变都行
}
else{//奇数
pu(stp,0);//将P放到辅助栈
st[stp].push_back(now);//入栈
id[now] = stp;//更新P在辅助栈内
q.push(stp);//辅助栈还有一个元素的位置
for(int j = i+1;j < nx;j++){
if(a[j] == y)pu(stx,0);//将全部Y入到X的栈内,Y全部消掉,最后只剩X
else simple(a[j]);//剩下正常相消
}
pu(stx,0);//将X放到该栈相消,该栈现在为空
st[stx].clear();
//清空当前栈
id[x] = id[y] = 0;//更新,X,Y全部被消掉
stp = stx;//当前栈为空,辅助栈进了P
//将该栈更新为辅助栈
}
}
i = nx;//因为循环内i会自动++,所以只需要赋值为r,自动r+1
}
}
printf("%d\n",ans.size());
for(int i = 0;i < ans.size();i++){//从0开始
if(ans[i].v2)printf("2 %d %d\n",ans[i].v1,ans[i].v2);
else printf("1 %d\n",ans[i].v1);
}
}
return 0;
}