长乐爆零之旅 day6 rps

版权声明:八月炊火的博客如需转载请注明出处 https://blog.csdn.net/qq_34990731/article/details/82952557

这一题好狗血,用递推空间炸了,0分,(哭死在厕所 )。
题目:
wzms今年举办了一场剪刀石头布大赛,bleavesbleaves被选为负责人。 比赛共有2^n 个人参加,分为2n轮, 在每轮中,第 1位选手和第 2位选手对战,胜者作为新的第 1位选手, 第 3位和第 4位对战,胜者作为新的第 2位选手,以此类推。 调查得知,每个人都有其偏爱决策,每个人在每一次对战中都会使用他的偏爱决策。 如果一次对战的双方的偏爱决策相同,那么这次对战就永远不会结束,所以 不希望这种情况发生。 现在 知道了每个人的偏爱决策,但她不知道如何安排初始的次序,使得上面的情况不会发生,你能帮帮她吗?
输入格式:
一行三个整数R,P,SR,P,S ,表示偏爱石头,布,剪刀的人数分别为R,P,SR,P,S 。
输出格式:
如果无解,输出 IMPOSSIBLE ; 否则输出一个长度为R+P+S的字符串,第 ii个字符表示初始时第 ii位选手的偏爱决策, 如果有多种方案,输出字典序最小的。
输入输出样例:
输入样例1:
1 1 0
输出样例1:
PR
输入样例2:
2 0 0
输出样例2:
IMPOSSIBLE
输入样例3:
1 1 2
输出样例3:
PSRS
说明:
样例解释1
只有 22个选手,一个偏爱石头,一个偏爱布,无论次序如何,偏爱布的选手都会胜出。 所以方案可以是 PRPR和 RPRP,其中字典序最小的 。
在这里插入图片描述

题解:
这一题还好不会太难,根据题目要求我们求最终的序列,可是我们发现极其不好求,那么我们换一种思路,我们枚举每种最后胜利者的偏爱(只有三种),根据规则由最后胜利者我们推到参赛者的偏爱,这样所有的问题就都在字典序上了,我们可以这样,我们dfs从1,不断往下dfs每次范围乘以二(和归并排序类似,我们不是排序而是分解),然后我们在回溯时左右两个区间我们可以根据字典序判断谁在左边(即前面),这样我们最后只要找到了就好了,如果没找到则输出IMPOSSIBLE 就好了,时间复杂度O(n log n)。
上代码:

#include<iostream>
#include<cstdio>
using namespace std;
int r,s,p,ans[1100000],n,R,S,P;//0是布即p,1是石头即r,2是剪刀即s 
void dfs(int x,int l,int r)//x表示我们的胜利者的偏爱,l和r表示参赛者的范围,就是总共2^n个人根据排序标号我们现在处理到[l,r]这个范围的人了 
{
	bool bj=false;//定义标记,在回溯时判断是否要调换 
	int mid=(l+r)>>1;
	if(l==r)//到了边界 
	{
		ans[l]=x;
		if(x==0)
			P++;
		if(x==1)
			R++;
		if(x==2)
			S++;
		return ;
	}
	if(x==0)//偏爱是布 
	{
		dfs(0,l,mid);
		dfs(1,mid+1,r);
	}
	if(x==1)//偏爱是石头 
	{
		dfs(1,l,mid);
		dfs(2,mid+1,r);
	}
	if(x==2)//偏爱是剪刀 
	{
		dfs(0,l,mid);
		dfs(2,mid+1,r);
	}
	for(int i=l;i<=mid;i++)//暴力判断 
	{
		if(ans[i]<ans[mid+i-l+1])
			break;
		if(ans[i]>ans[mid+i-l+1])
		{
			bj=true;
			break;
		}
	}
	if(bj)//暴力交换 
		for(int i=l;i<=mid;i++)
			swap(ans[i],ans[mid+i-l+1]);
}
int main()
{
	int x;
	scanf("%d %d %d",&r,&p,&s);
	x=r+s+p;//计算一下总共x个人 
	for(int i=0;i<=2;i++)//枚举胜利者的偏爱 
	{
		R=0;//清空一下 
		S=0;//这三个是我们用来统计当前情况下三种偏爱的人的个数 
		P=0;
		dfs(i,1,x);
		if(R==r && S==s && P==p)//如果与题目相符合 
		{
			for(int i=1;i<=x;i++)//输出 
			{
				if(ans[i]==0)
					printf("P");
				if(ans[i]==1)
					printf("R");
				if(ans[i]==2)
					printf("S");
			}
			cout <<endl;
			return 0;//记得直接return掉,要不然下面的IMPOSSIBLE要用标记 
		}
	}
	printf("IMPOSSIBLE");//没有输出的话 
	return 0;
}                 

明天就要回去了,(不想军训 )。

猜你喜欢

转载自blog.csdn.net/qq_34990731/article/details/82952557