一开始想写暴力但毫无思路。。
不过我们可以把问题化简,假如给你知道了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;
}