1. 程式人生 > >Codeforces 1086D Rock-Paper-Scissors Champion

Codeforces 1086D Rock-Paper-Scissors Champion

Description

\(N\) 個人排成一排, 每個人都事先決定出剪刀、石頭、布。

每次可以任意選兩個相鄰的人進行決鬥。 規則和遊戲一樣。

但是如果平局, 則擲硬幣來決定勝負。 輸的人下場。

現要求出有幾個人 有獲勝的可能(即可以任意決定決鬥的順序 和 擲出的硬幣)

Solution

一個很顯然的結論: 一個人要想獲勝, 兩邊都要滿足其中一個條件, 以左邊為例:

左邊沒有能贏他的人, 或者 左邊存在一個他能贏的人即可。

根據這個結論, 我們分別計算出剪刀 、石頭、 布的人有多少人能贏。

以計算出剪刀有多少人能贏為例, 先找出最先出布的人和最後出布的人, 這兩個人中間的人都可以贏, 記入貢獻

然後再剩餘出剪刀的人 左邊沒有人出石頭 和 右邊沒有人出石頭的人的個數。

\(Bit\)\(Set\) 可以\(O(logN)\)計算。

Code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<set>
#define up(a, b) (a = a > b ? a : b)
#define down(a, b) (a = a > b ? b : a)
#define cmax(a, b) (a > b ? a : b)
#define cmin(a, b) (a > b ? b : a)
#define Abs(a) ((a) > 0 ? (a) : -(a))
#define lowbit(x) ((x) & -(x))
#define rd read()
#define db double
#define LL long long
using namespace std;
typedef pair<int, int> P;

/*
inline char nc(){
    static char buf[1<<14],*p1=buf,*p2=buf;
    return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,1<<14,stdin),p1==p2)?EOF:*p1++;
}
inline LL read(){
    char c=nc();LL x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=nc();}
    while(c>='0'&&c<='9'){x=x*10+c-'0',c=nc();}
    return x*f;
}
*/


int read() {
    int X = 0, p = 1; char c = getchar();
    for (; c > '9' || c < '0'; c = getchar())
        if (c == '-') p = -1;
    for (; c >= '0' && c <= '9'; c = getchar())
        X = X * 10 + c - '0';
    return X * p;
}

const int N = 2e5 + 5;

int n, m, sum[4][N];
char s[N];
set<int> S[4];

int ch(char c) {
    if (c == 'R')
        return 0;
    if (c == 'P')
        return 1;
    if (c == 'S')
        return 2;
}

void add(int x, int d, int *p) {
    for (; x <= n; x += lowbit(x))
        p[x] += d;
}

int query(int x, int *p) {
    if (x < 0) return 0;
    int res = 0;
    for (; x; x -= lowbit(x))
        res += p[x];
    return res;
}

int work(int x) {
    int y = (x + 2) % 3; //x > y
    int z = (x + 1) % 3; //z > x 
    int res = 0;
    if (!S[y].size()) {
        if (S[z].size())
            return 0;
        else return n;
    }
    int l = *(S[y].begin()), r = *(--S[y].end());
    if (S[y].size() > 1) 
        res += query(r, sum[x]) - query(l - 1, sum[x]);
    int tmp = S[z].size() ? *(S[z].begin()) : n + 1;
    down(tmp, l);
    res += query(tmp, sum[x]);

    tmp = S[z].size() ? *(--S[z].end()) : 0;
    up(tmp, r);
    res += query(n, sum[x]) - query(tmp - 1, sum[x]);
    return res;
}

int main()
{
    n = rd; m = rd;
    scanf("%s", s + 1);
    for (int i = 1; i <= n; ++i) {
        add(i, 1, sum[ch(s[i])]);
        S[ch(s[i])].insert(i);
    }
    printf("%d\n", work(0) + work(1) + work(2));
    for (int i = 1; i <= m; ++i) {
        int x = rd; char c = getchar();
        for (; !(c == 'R' || c == 'P' || c == 'S');)
            c = getchar();
        S[ch(s[x])].erase(x); add(x, -1, sum[ch(s[x])]);
        s[x] = c;
        S[ch(s[x])].insert(x); add(x, 1, sum[ch(s[x])]);
        printf("%d\n", work(0) + work(1) + work(2));
    }
}