首页 > 其他分享 >【洛谷P8866】喵了个喵

【洛谷P8866】喵了个喵

时间:2022-12-01 23:33:21浏览次数:64  
标签:洛谷 res 元素 卡牌 st P8866 空栈 栈底

题目

题目链接:https://www.luogu.com.cn/problem/P8866
小 E 喜欢上了一款叫做《喵了个喵》的游戏。这个游戏有一个牌堆和 \(n\) 个可以从栈底删除元素的栈,任务是要通过游戏规则将所有的卡牌消去。开始时牌堆中有 \(m\) 张卡牌,从上到下的图案分别是 \(a_1, a_2,\dots, a_m\)。所有的卡牌一共有 \(k\) 种图案,从 \(1\) 到 \(k\) 编号。牌堆中每一种图案的卡牌都有偶数张。开始时所有的栈都是空的。这个游戏有两种操作:

  • 选择一个栈,将牌堆顶上的卡牌放入栈的顶部。如果这么操作后,这个栈最上方的两张牌有相同的图案,则会自动将这两张牌消去。
  • 选择两个不同的栈,如果这两个栈栈的卡牌有相同的图案,则可以将这两张牌消去,原来在栈底上方的卡牌会成为新的栈底。如果不同,则什么也不会做。

这个游戏一共有 \(T\) 关,小 E 一直无法通关。请你帮小 E 设计一下游戏方案,即对于游戏的每一关,给出相应的操作序列使得小 E 可以把所有的卡牌消去。

\(n\leq 300,\sum m\leq 2\times 10^6,k\in\{2n-2,2n-1\}\)。

思路

首先 \(k=2n-2\) 的很好做,每一个元素与其前\(/\)后一个相同元素匹配,把至多两个元素放在一个栈中,消除的时候在栈顶就直接放到栈里,在栈底就放在最后一个空栈里。
\(k=2n-1\) 的时候,可能出现 \(n-1\) 个栈都放了两个元素,但是下一个元素不存在于任何栈中的情况。无论是将这个元素放在最后一个栈,或是任意一个已经放了两个元素的栈中,都可能导致无法消除。
假设一个有两个元素的栈,栈底为 \(x\),栈顶为 \(y\),观察到,如果将这最后一个元素 \(z\) 放在这个栈上面,若在牌堆中下一个 \(x\) 出现的比下一个 \(y\) 早,那么其实不会有任何的影响。因为利用最后一个空栈将 \(x\) 消除后,又会变为原来的情况。
如果所有栈都不满足下一个 \(x\) 出现的比下一个 \(y\) 早,那么只需要将 \(z\) 放在那个空栈中,然后把 \(n\) 个 \(x\) 中在牌堆中最早出现的那一个所在的栈设为新的空栈即可。因为这一个 \(x\) 一定可以通过操作 \(1\) 来消除。
需要注意的是,当一个栈被定义为“空栈”的时候,无论那个栈是否还存在元素,都不可以往里面再添加元素,直到下一次特殊情况出现。否则可能导致因为加入新的元素,这个栈底无法通过操作 \(1\) 来消除。
实现的话我比较无脑,直接维护 \(4\) 个 \(\rm set\),分别储存 有 \(0\) 个元素(注意不等价于上文的“空栈”,那个“空栈”是用来处理特殊情况的空栈)\(\ /\ 1\) 个元素\(\ /\ 2\) 个元素且 \(x\) 先于 \(y\ /\ 2\) 个元素且 \(x\) 后于 \(y\) 的栈的编号。注意“空栈”需要特殊记下来。
时间复杂度 \(O(m\log n)\)。

代码

#include <bits/stdc++.h>
#define mp make_pair
#define fi first
#define se second
using namespace std;

const int N=610,M=2000010;
int Q,n,m,k,pos,a[M],bel[N],st[N][4];
queue<pair<int,int> > q;
set<int> s0,s1,s2,s3;
vector<int> nxt[N];

int main()
{
	scanf("%d",&Q);
	while (Q--)
	{
		s0.clear(); s1.clear(); s2.clear(); s3.clear();
		scanf("%d%d%d",&n,&m,&k);
		for (int i=1;i<=m;i++) scanf("%d",&a[i]);
		for (int i=m;i>=1;i--) nxt[a[i]].push_back(i);
		for (int i=2;i<=n;i++) s0.insert(i);
		pos=1;
		for (int i=1;i<=m;i++)
		{
			nxt[a[i]].pop_back();
			int p=bel[a[i]];
			if (!p)
			{
				if (s0.size())
				{
					int id=*s0.begin();
					q.push(mp(id,-1));
					s1.insert(id); s0.erase(s0.begin());
					st[id][1]=a[i]; bel[a[i]]=id;
				}
				else if (s1.size())
				{
					int id=*s1.begin();
					if (id==pos) id=*(++s1.begin());
					q.push(mp(id,-1));
					s1.erase(s1.find(id));
					if (nxt[st[id][1]].back()>nxt[a[i]].back()) s2.insert(id);
					if (nxt[st[id][1]].back()<nxt[a[i]].back()) s3.insert(id);
					st[id][2]=a[i]; bel[a[i]]=id;
				}
				else if (s3.size())
				{
					int id=*s3.begin();
					q.push(mp(id,-1));
					st[id][3]=a[i]; bel[a[i]]=id;
				}
				else
				{
					q.push(mp(pos,-1));
					s1.insert(pos);
					st[pos][1]=a[i]; bel[a[i]]=pos;
					for (int j=i+1;j<=m;j++)
						if (st[bel[a[j]]][1]==a[j]) { pos=bel[a[j]]; break; }
				}
			}
			else if (st[p][1]==a[i] && !st[p][2])
			{
				q.push(mp(p,-1));
				s1.erase(s1.find(p));
				st[p][1]=0; bel[a[i]]=0;
				if (p!=pos) s0.insert(p);
			}
			else if (st[p][2]==a[i])
			{
				q.push(mp(p,-1));
				s1.insert(p); s2.erase(s2.find(p));
				st[p][2]=0; bel[a[i]]=0;
			}
			else if (st[p][3]==a[i])
			{
				q.push(mp(p,-1));
				st[p][3]=0; bel[a[i]]=0;
			}
			else if (st[p][1]==a[i] && st[p][2])
			{
				q.push(mp(pos,-1)); q.push(mp(pos,p));
				if (!st[p][3])
				{
					s1.insert(p); s3.erase(s3.find(p));
					st[p][1]=st[p][2]; st[p][2]=0;
				}
				else
				{
					if (nxt[st[p][2]].back()>nxt[st[p][3]].back())
						s2.insert(p),s3.erase(s3.find(p));
					st[p][1]=st[p][2]; st[p][2]=st[p][3]; st[p][3]=0;
				}
				bel[a[i]]=0;
			}
		}
		printf("%d\n",(int)q.size());
		for (;q.size();q.pop())
		{
			pair<int,int> res=q.front();
			if (res.se==-1) printf("1 %d\n",res.fi);
			if (res.se!=-1) printf("2 %d %d\n",res.fi,res.se);
		}
	}
	return 0;
}

标签:洛谷,res,元素,卡牌,st,P8866,空栈,栈底
From: https://www.cnblogs.com/stoorz/p/16943135.html

相关文章

  • 洛谷 P1891 疯狂 LCM
    \(\text{lcm}\)不好处理,转化为\(\gcd\):\[n\sum_{i=1}^n\frac{i}{\gcd(i,n)}\]\(\gcd\)相关题目的套路——枚举因数:\[n\sum_{d|n}\sum_{i=1}^n\fracid[......
  • 洛谷 P4552 [Poetize6] IncDec Sequence(差分)
    题目分析直接贴一个洛谷上的题解,真的秀,讲的又清楚又好要使得序列的数全部相等,其实就是让他们之间的差全为0,也就是差分序列的除了第一项每一项都是0,为什么除了第一项呢,因......
  • 洛谷 P1387 最大正方形(前缀和,二分)
    题目分析当一个边长为x的正方形不包含0时,这个正方形内的二维前缀和为x*x,题目想求满足条件的最大的正方形的边长假如最大的正方形的边长为ans,那么凡是边长大于ans的正方形......
  • 洛谷 P1205 [USACO1.2] 方块转换 Transformations
    [USACO1.2]方块转换Transformations题目描述一块\(n\timesn\)正方形的黑白瓦片的图案要被转换成新的正方形图案。写一个程序来找出将原始图案按照以下列转换方法转......
  • 洛谷-P5541 Sleepy Cow Herding S
    SleepyCowHerdingSSleepyCowSorting的升级版,从\(3\)头牛变成\(n\)的情况分类讨论+双指针先把答案本就连续的特判丢掉最大值最大值就尽量把每个空位......
  • P8866 [NOIP2022] 喵了个喵
    \(\mathcalLink\)当\(k=2n-2\):保证任意时刻每种元素只出现一次,并保留一个空栈,让其他栈大小不超过\(2\)即可。当\(k=2n-1\):延续上面的做法,对于多出来的第\(2n-1\)......
  • 洛谷P2014 [CTSC1997] 选课
    sloj P2006.「树上背包」选课题目描述在大学里每个学生,为了达到一定的学分,必须从很多课程里选择一些课程来学习,在课程里有些课程必须在某些课程之前学习,如高等数学总......
  • 洛谷P2015 二叉苹果树
    slojP10153.「一本通5.2例1」二叉苹果树P2015二叉苹果树题目描述有一棵苹果树,如果树枝有分叉,一定是分二叉(就是说没有只有一个儿子的结点)这棵树共有N个结点(叶子......
  • 洛谷 P4018 Roy&October之取石子
    洛谷P4018Roy&October之取石子题意:\(n\)个石头,每次取\(p^k\)个石子(\(p\)是质数,\(k\in\N\)),取完最后一个的人获胜,问谁有必胜策略。只能说,MO题真的猛!结论:\(n\bmod......
  • 洛谷P1090 Java
    [NOIP2004提高组]合并果子/[USACO06NOV]FenceRepairG题目描述在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆。多多决定把所有的......