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

· · 题解

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

这道题我们可以把剪刀、石头、布想象成一个食物链中的三个点,剪刀的“天敌”是石头,“猎物”是布,同理可得石头和剪刀的天敌和猎物。
又因为剪刀的猎物是剪刀天敌的天敌,所以我们可以得出在以下几个情况中,剪刀可以胜:

  1. 在一个排列中,若只有剪刀和布,则拿剪刀的人都一定可以胜,拿布的人一定输。例如: :::align{center} SSPPSPS

    :::

  2. 在一个排列中,若剪刀的左边有石头而右边没有,且左边有布,则拿剪刀的人可以胜利。例如: :::align{center} RPPSPSP

    :::

  3. 在一个排列中,若剪刀的右边有石头而左边没有,且右边有布,则拿剪刀的人可以胜利。例如: :::align{center} SSPRRP

    :::

  4. 在一个排列中,若剪刀的左边和右边都有石头,但是左右边都有布,则拿剪刀的人可以胜利。例如: :::align{center} RPPRRSSPSRRP

    ::: 同时,我们不必考虑剪刀、石头、布三者之间的位置关系,因为如果是 SRSP 这种情况,可以让石头战胜它右边的剪刀,再让布战胜石头,最后再让左边的剪刀战胜布就行了。
    可以用一个数组 a 记录当前区间左边和右边各个区间种类的数量,方便判断左右的区间以记录是否可以胜利。
    因为若两张相同的卡片比赛,则谁都可以胜利,所以可以把每个连续的持有相同卡片的人记录到数组 c 中,在记录每一个区间是否可以胜利,再遍历一遍所有人的卡片,看在哪一个区间里,若这个区间里人可以胜利输出 1,不可以胜利则输出 0

代码

#include <bits/stdc++.h>
using namespace std;
int n , cnt;
string s;
char c[200005] = {'1'};
int a[5][5];
int ans[200005];
int main()
{
    cin >> n;
    cin >> s;
    for(int i = 0; i < n; i++)
    {
        if(s[i] != c[cnt])
        {
            cnt ++;
            c[cnt] = s[i];//记录每一个持有相同卡片的区间
            if(s[i] == 'S')
            {
                a[1][0] ++;
            }
            else if(s[i] == 'R')
            {
                a[1][1] ++;
            }
            else
            {
                a[1][2] ++;
            }
            //记录左右的区间种类,0为左边,1为右边
            //第一个区间在最左边,所以只有右边的区间
        }
    }
    for(int i = 1; i <= cnt; i++)
    {
        if(c[i] == 'S')
        {
            if(a[0][1] == 0 && a[1][1] == 0) ans[i] = 1;
            else if(a[0][1] == 0 && a[1][2] != 0) ans[i] = 1;
            else if(a[0][2] != 0 && a[1][1] == 0) ans[i] = 1;
            else if(a[0][2] != 0 && a[1][2] != 0) ans[i] = 1;
            a[0][0] ++;
            a[1][0] --;//区间左移
        }
        if(c[i] == 'R')
        {
            if(a[0][2] == 0 && a[1][2] == 0) ans[i] = 1;
            else if(a[0][2] == 0 && a[1][0] != 0) ans[i] = 1;
            else if(a[0][0] != 0 && a[1][2] == 0) ans[i] = 1;
            else if(a[0][0] != 0 && a[1][0] != 0) ans[i] = 1;
            a[0][1] ++;
            a[1][1] --;
        }
        if(c[i] == 'P')
        {
            if(a[0][0] == 0 && a[1][0] == 0) ans[i] = 1;
            else if(a[0][0] == 0 && a[1][1] != 0) ans[i] = 1;
            else if(a[0][1] != 0 && a[1][0] == 0) ans[i] = 1;
            else if(a[0][1] != 0 && a[1][1] != 0) ans[i] = 1;
            a[0][2] ++;
            a[1][2] --;
        }//判断每个区间是否可以胜利
    }
    for(int i = 0 , op = 1; i < n; i++)
    {
        if(s[i] != c[op]) op ++;
        if(ans[op]) cout << "1";
        else cout << "0";//判断是否可以胜利
    }
    return 0;
}

完结撒花!