【CCPC】2022绵阳站 M. Rock-Paper-Scissors Pyramid | 栈

284 阅读2分钟

本文已参与「新人创作礼」活动, 一起开启掘金创作之路。

【CCPC】绵阳站 M. Rock-Paper-Scissors Pyramid | 栈

题目链接

Problem - M - Codeforces

题目

image.png

  • If the two blocks immediately below a block have the same shape (namely, both are R, P, or S), we will place the same shape on the block.
  • If the two blocks immediately below a block have different shapes, we will place the winning shape on the block.

Refer to the pictures in the notes section for a clearer illustration.

Bobo wants to know, following this rule, what is the shape at the top of the pyramid?

image.png

题目大意

有一个长度为 nn 的手势序列,仅由 RSP 构成。其中 R 表示石头;S 表示剪刀;P 表示布。

共进行 n1n-1 轮游戏,每轮游戏每相邻的两个手势进行游戏,胜利者留下,如果平局则留下任意一个。每轮游戏后,手势序列的长度将会减少 1。在 n1n-1 轮游戏结束后输出最后胜利的手势。

游戏过程类似一个金字塔形状,可以参考上图的样例解释。

思路

我们先模拟这个过程,容易发现一层一层模拟是不可做的,我们斜着模拟。

从左到右每增加一个数字,该数字就需要逐层攀爬金字塔,与斜着的金字塔右腰上的每一个手势比较。假设我们现在处理到了 aia_i,那么我们首先要和 ai1a_{i-1} 比较,如果胜利就向上攀爬一层,和 win(ai2,ai1)win(a_{i-2},a_{i-1}) 比较……直到爬上 [1,i][1,i] 金字塔的顶峰,或者在中途输掉。如果 aia_i 在攀爬途中输掉,就会换成此次与 aia_i 比较的那个手势取代 aia_i 继续向上攀爬。

容易发现用 aia_i 更新完之后 [1,i][1,i] 金字塔的右腰自下而上变成了:

  • 连续 aia_i 胜利次数个 aia_i
  • aia_i 第一次失败开始沿着 [1,i1][1,i-1] 金字塔到顶端的所有元素。

又因为显然若干个相同手势可以压成一个手势,整个过程就可以抽象为维护一个栈:每次加入新的手势 aia_i 时一直退栈直到栈顶元素将会赢过 aia_i,然后让手势 aia_i 入栈。所有元素入栈后输出栈顶元素即可。

代码

#include <stdio.h>
#include <string.h>
const int N=1000005;
char a[N];
char q[N];
int tot;
int check(char a,char b)
{
	if (a=='S'&&b=='R') return 0;
	if (a=='R'&&b=='P') return 0;
	if (a=='P'&&b=='S') return 0;
	return 1;
}
char solve()
{
	scanf("%s",a+1);
	int n=strlen(a+1);
	tot=0;
	for (int i=1;i<=n;++i)
	{
		while (tot!=0&&check(a[i],q[tot])) tot--;
		q[++tot]=a[i];
	}
	return q[1];
}
int main()
{
	int T;
	for (scanf("%d",&T);T--;)
		printf("%c\n",solve());
        return 0;
}