XXII Open Cup. Grand Prix of Seoul E

本文针对Codeforces上的一道题目E进行了详细的解析,提出了一种O(n)的时间复杂度算法来解决问题,即如何通过有限轮次的游戏使得由R、S、P组成的字符串达到稳定状态。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:Problem - E - Codeforces

 题意:输入一个长度为n的字符串,由R、S、P三种字符组成。分别代表石头、剪刀、布。每一轮游戏,从左往右遍历,每相邻的两位进行游戏,若第i位能赢过第i+1位(石头剪刀布的规则),那么两位互换,遍历字符串一遍算一轮游戏。输出原字符串进行T轮游戏后的结果。

        因为n,T的范围都很大,模拟肯定是不现实的。所以,可以想想O(n)的做法。三个字母都在的情况很难考虑,那就简化问题。在一个字符串中,如果只有两种字母,那么显然,在游戏进行足够多轮后,二者之中的败者会在字符串的前部,胜者会在字符串的后部。然后就要证明,不同段只含两个字母的字符串之间不会互相影响。显然当一串字符串中出现第三种字符时,因为前二者的胜者在后,显然,前二者的胜者不可能胜过第三种字符。比如,RS的字符串,结尾是R,R不能胜过P,因此,不同段的字符串之间不会互相影响,不会出现跨区的交换。

        因此,该题可以简化为多段只含两个字母的字符串的问题。而对于每一段中的败者,假设他在该段的第i位,是该段中第k个败者,那么他的位置为max(k,i-T);O(n)时间能解决该题。

#include<bits/stdc++.h>
using namespace std;
char st[503500];
int a[503500],p[5],pos,lossf,winf,cnt;
long long n,T;
bool f[10];
long long max0(long long x,long long y)
{
	if (x>y) return x;
	return y;
}
void swap(int x,int y)
{
	int t;
	t=a[x];a[x]=a[y];a[y]=t;
}
int main()
{
	scanf("%lld%lld",&n,&T);
	scanf("%s",st+1);
	for (int i=1;i<=n;i++)
	{
		if (st[i]=='R') a[i]=1;
		if (st[i]=='S') a[i]=2;
		if (st[i]=='P') a[i]=3;
 	}
 	f[1]=true;f[2]=true;f[3]=true;
 	f[a[1]]=false;cnt=1;
 	int l=1;
 	for (int i=2;i<=n;i++)
 	{
 		if (f[a[i]])
		{
			if (cnt<=1)
			{
				cnt++;
				p[cnt]=a[i];
			}
			else
			{
				
				if (f[3]) {lossf=2;winf=1;}
				if (f[1]) {lossf=3;winf=2;}
				if (f[2]) {lossf=1;winf=3;}
				int k=0;
				for (int j=l;j<=i-1;j++)
				{
					if (a[j]==lossf) 
					{
						k++;pos=max0(l+k-1,j-T);
						swap(j,pos);
					}
				}
				f[1]=true;f[2]=true;f[3]=true;
				cnt=1;
				p[cnt]=a[i];
				l=i;
			} 
			f[a[i]]=false;
		}	
	}
	if (cnt==2)
	{
			if (f[3]) {lossf=2;winf=1;}
			if (f[1]) {lossf=3;winf=2;}
			if (f[2]) {lossf=1;winf=3;}
			int k=0;
			for (int j=l;j<=n;j++)
			{
				if (a[j]==lossf) 
				{
					k++;pos=max0(l+k-1,j-T);
					swap(j,pos);
				}
			}
	}
	for (int i=1;i<=n;i++)
	{
		if (a[i]==1) printf("R");
		if (a[i]==2) printf("S");
		if (a[i]==3) printf("P");
	}
	return 0;
} 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值