自己试了几组数据可以,提交爆零
#include<bits/stdc++.h>
using namespace std;
int t, n, m, k;//组数, 栈数, 牌数, 种数
int a[2000005], loc[605], stk[305][5];//牌堆, 牌u所在栈的标号, 栈
int head[5], nxt[305], pre[305];//大小为i的栈链表表头, 后继标号, 前驱标号
int tmp;
/*与前几篇题解不同的是, 如果第2n-1种牌u后面第一张栈底牌bot, bot所在栈为v
若v栈顶牌top有出现在s之前, 无论多少张, 都把u放入空栈, 同时记v为tmp
此后利用tmp为标记, 将v当作空栈, 将其余top当作正常顶牌, 放入大小为1的栈
因为bot前都是栈顶牌, 这样不用判断top数量奇偶也能正常消除*/
int sum, ans[4000005][3];//记操作数, 操作
void change(int k, int i){//将大小改变的栈k, 转移到另一链表
int num = -1;
while(stk[k][++num]);//计算当前栈大小
if(nxt[k]) pre[nxt[k]] = pre[k];
if(pre[k]) nxt[pre[k]] = nxt[k];
else head[num - i] = nxt[k];//链表删除
if(head[num]) pre[head[num]] = k;
nxt[k] = head[num]; head[num] = k; pre[k] = 0;//链表插入
}
void op(int i, int u, int v){//记录操作
ans[++sum][0] = i;
ans[sum][1] = u;
ans[sum][2] = v;
}
int main(){
scanf("%d", &t);
while(t--){
memset(stk, 0, sizeof stk);
memset(loc, 0, sizeof loc);
memset(head, 0, sizeof head);
sum = 0;
scanf("%d%d%d", &n, &m, &k);
pre[1] = 0; nxt[n] = 0; head[0] = 1;
for(int i = 1; i < n; i++){
nxt[i] = i + 1;
pre[i + 1] = i;
}//链表初始化
for(int i = 1; i <= m; i++)
scanf("%d", &a[i]);
for(int i = 1; i <= m; i++){
int u = a[i];
if(loc[u]){//如果栈中有牌u
int v = loc[u];
if(stk[v][0] == u && stk[v][1]){//如果u在栈底, 放入空栈消除
int w = head[0];
op(1, w, 0);
op(2, v, w);
stk[v][0] = stk[v][1];
stk[v][1] = stk[v][2];
stk[v][2] = 0;
loc[u] = 0;
change(v, -1);
}
else{//如果u在栈顶, 直接消除
op(1, v, 0);
if(stk[v][1]) stk[v][1] = 0;
else stk[v][0] = 0;
loc[u] = 0;
change(v, -1);
}
}
else{//如果栈中无u
if(head[1]){//如果有大小为1的栈, 放入栈顶
int v = head[1];
if(!head[0] && v == tmp) v = nxt[v];
//如果没有大小为0的栈, 说明有个大小1的栈被当做空栈
op(1, v, 0);
stk[v][1] = u;
loc[u] = v;
change(v, 1);
}
else if(nxt[head[0]]){//如果有至少两个空栈
int v = head[0];
op(1, v, 0);
stk[v][0] = u;
loc[u] = v;
change(v, 1);
}
else{//该牌为第2n-1种
int v = head[0], j = i + 1;
while(a[j] != u && stk[loc[a[j]]][0] != a[j]) j++;
//找到u后第一个栈底牌或u
if(a[j] == u){//如果是u, 放空栈
op(1, v, 0);
stk[v][0] = u;
loc[u] = v;
change(v, 1);
}
else{//如果是栈底牌
int w = loc[a[j]], s = i + 1;
while(s < j && a[s] != stk[w][1]) s++;
//判断当中有无栈顶牌
if(s == j){//没有栈顶就放到该栈
op(1, w, 0);
stk[w][2] = u;
loc[u] = w;
change(w, 1);
}
else{//有栈顶则放入空栈
tmp = w;//假装该栈为空
op(1, v, 0);
stk[v][0] = u;
loc[u] = v;
change(v, 1);
}
}
}
}
}
printf("%d\n", sum);
for(int i = 1; i <= sum; i++){
int j = 0;
while(ans[i][j] && j < 3){
printf("%d ", ans[i][j]);
j++;
}
printf("\n");
}//输出
}
return 0;
}