【题解】ACM Rock-Paper-Stones (前缀和)

一开始想写暴力但毫无思路。。

不过我们可以把问题化简,假如给你知道了x,y,z,该如何计算两个人的胜利情况?

我们设第一个人为小A,第二个人为小B,小B要出的招式已经在输入里给出了,现在我们得对小A的应对策略进行操作,我们会想到利用前缀和来解决这个问题。初始化三个前缀和数组sumS、sumP、sumR为0,代表小B的招式里出的剪刀 布 石头 的个数,我们扫一遍小B读入的字符串,如果读到某一个位置为R,那么sumR[i]=sumR[i-1]+1。否则sumR[i]=sumR[i-1]。对sumP和sumS也是同理。接下来用ansA代表小A的胜场,ansB代表小B的胜场,因为xyz都是已知的,并且小A的出法一定是按照石头布剪刀来进行的,所以小A的胜场就是三段区间内小B出剪刀、石头、布的次数,由于我们用前缀和记录了,所以可以比较容易的得到这个数值。对于小B的胜场,因为小A在特定区间内只会出石头布剪刀,所以小B的胜场就是三段区间内自己出布、剪刀、石头的次数,前缀和同样求出。如果ansA>ansB 那么结果就++;

这是对于x,y,z已知的情况。如果是未知的,那我们只好循环枚举来解决,循环x从0到n(注意从0开始,因为可以不出),循环y从0到n-x,因为x+y+z=n,所以直接表示出z即可,在循环内进行上一段的操作。当然,前缀和我们房在循环外求就可以了。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int t;
int tot;
char s[1010];
int sumR[1010];
int sumS[1010];
int sumP[1010];
int main()
{
	scanf("%d",&t);
	while(t--)
	{
		tot=0;
		int n;
		cin>>n;
		for(int i=1;i<=n;i++)
		{
			cin>>s[i];
		}
		sumR[0]=sumS[0]=sumP[0]=0;
		for(int i=1;i<=n;i++)
		{
			if(s[i]=='R')
			{
				sumR[i]=sumR[i-1]+1;
			}
			else sumR[i]=sumR[i-1];
			
			if(s[i]=='P')
			{
				sumP[i]=sumP[i-1]+1;
			}
			else sumP[i]=sumP[i-1];
			
			if(s[i]=='S')
			{
				sumS[i]=sumS[i-1]+1;
			}
			else sumS[i]=sumS[i-1];
		}
		for(int x=0;x<=n;x++)
		{
			for(int y=0;y<=n-x;y++)
			{
				int z=n-x-y;
				int ansA,ansB=0;
				ansA=(sumS[x]-sumS[0])+(sumR[x+y]-sumR[x])+(sumP[n]-sumP[x+y]);
				ansB=(sumP[x]-sumP[0])+(sumS[x+y]-sumS[x])+(sumR[n]-sumR[x+y]);
				if(ansA>ansB) tot++;
			}
		}
		cout<<tot<<endl;
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Rem_Inory/article/details/81171140