求助
查看原帖
求助
913828
Red_bean11楼主2023/6/25 23:05

自己试了几组数据可以,提交爆零

#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;

}
2023/6/25 23:05
加载中...