题解:P17135 [KOI 2026 #1] 剪刀石头布

· · 题解

P17135 [KOI 2026 #1] 剪刀石头布题解

很简单的一道题,赛时直接秒了。
可以发现,只要左右两边可以通过操作使其只剩下与当前手势相同的手势或被当前手势克制的手势就可以获胜,那么如何做到这一点呢?当任意一边出现克制当前手势的手势时,如果这一边也有被当前手势克制的手势就可以让它们不断靠拢,最后让它们打一场,然后就只剩下被当前手势克制的手势,以此类推就可以获胜反之则不能获胜。
虽然分左右两边考虑,但实际上都差不多,先定义一个前缀和数组 bb[1][i]b[2][i]b[3][i] 分别表示前 i 个里面剪刀、石头、布的个数,再定义一个后缀和数组 b1,令 b1[x][i]=b[x][n]-b[x][i-1]; 表示后 i 个里面编号为 x 的手势的个数。然后按找上面的思路写就行了。

Code

#include<bits/stdc++.h>
using namespace std;
int n,b[4][200005],b1[4][200005];
string s;
int main()
{
    //freopen("battle.in","r",stdin);
    //freopen("battle.out","w",stdout);
    cin>>n;
    cin>>s;
    for(int i=0;i<n;i++)
    {
        b[1][i+1]=b[1][i]+(s[i]=='P');
        b[2][i+1]=b[2][i]+(s[i]=='R');
        b[3][i+1]=b[3][i]+(s[i]=='S');
    }
    for(int i=1;i<=n;i++)
    {
        b1[1][i]=b[1][n]-b[1][i-1];
        b1[2][i]=b[2][n]-b[2][i-1];
        b1[3][i]=b[3][n]-b[3][i-1]; 
    }
    if(s[0]=='S'&&(b1[1][2]>0||b[3][n]==n))cout<<"1";
    else if(s[0]=='P'&&(b1[2][2]>0||b[1][n]==n))cout<<"1";
    else if(s[0]=='R'&&(b1[3][2]>0||b[2][n]==n))cout<<"1";
    else cout<<'0';
    for(int i=1;i<n-1;i++)
    {
        if(s[i]=='S'&&(b[1][i]>0||b[3][i]==i)&&(b1[1][i+1]>0||b1[3][i+1]==n-i))cout<<"1";
        else if(s[i]=='P'&&(b[2][i]>0||b[1][i]==i)&&(b1[2][i+1]>0||b1[1][i+1]==n-i))cout<<"1";
        else if(s[i]=='R'&&(b[3][i]>0||b[2][i]==i)&&(b1[3][i+1]>0||b1[2][i+1]==n-i))cout<<"1";
        else cout<<'0';
    }
    if(n!=1)
    {
        if(s[n-1]=='S'&&(b[1][n]>0||b[3][n]==n))cout<<"1";
        else if(s[n-1]=='P'&&(b[2][n]>0||b[1][n]==n))cout<<"1";
        else if(s[n-1]=='R'&&(b[3][n]>0||b[2][n]==n))cout<<"1";
        else cout<<'0'; 
    }
    return 0;
}

码风不太好请原谅。