Colouring Game (Codeforces 1704F)
Tags: Others, games

Alice and Bob are playing a game. There are $$$n$$$ cells in a row. Initially each cell is either red or blue. Alice goes first.On each turn, Alice chooses two neighbouring cells which contain at least one red cell, and paints that two cells white. Then, Bob chooses two neighbouring cells which contain at least one blue cell, and paints that two cells white. The player who cannot make a move loses.Find the winner if both Alice and Bob play optimally.Note that a chosen cell can be white, as long as the other cell satisfies the constraints.

Input: The first line contains a single integer $$$t$$$ ($$$1 \leq t \leq 10^4$$$) — the number of test cases. Description of test cases follows.For each test case, the first line contains an integer $$$n$$$ ($$$2 \leq n \leq 5 \cdot 10^5$$$) — the number of cells.The second line contains a string $$$s$$$ of length $$$n$$$ — the initial state of the cells. The $$$i$$$-th cell is red if $$$s_i = $$$ R, blue if $$$s_i = $$$ B.It is guaranteed that the sum of $$$n$$$ over all test cases does not exceed $$$5 \cdot 10^5$$$.

Output: For each test case, output the name of the winner on a separate line.

Note: In the notes, the cell numbers increase from left to right.In the first testcase for Alice, she has two choices: paint the first and the second cells, or paint the second and the third cells. No matter what choice Alice makes, there will be exactly one blue cell after Alice's move. Bob just needs to paint the blue cell and its neighbour, then every cell will be white and Alice can't make a move. So Bob is the winner.In the second testcase no matter what Alice chooses, Bob can choose to paint the fourth and fifth cells in $$$2$$$ turns.In the third testcase at first, Alice paints the third and the fourth cells. It doesn't matter if Bob paints the first and the second cells or the fifth and sixth cells, as Alice can paint the other two cells.In the fourth testcase at first, Alice paints the second and the third cells. If Bob paints the fifth and the sixth cells or the fourth and the fifth cells, then Alice paints the seventh and the eighth cells. If Bob paints the seventh and the eighth cells, then Alice paints the fifth and the sixth cells.In the fifth Alice chooses the middle two cells at first, then Bob obviously has only two options, whichever variant he chooses, Alice can choose the other one and win.In the eighth no matter what Alice chooses, Bob can choose the other two symmetrical cells.

Sample Inputs:
8
3
BRB
5
RRBBB
6
RBRBRB
8
BBRRBRRB
6
BRRBRB
12
RBRBRBRBRRBB
12
RBRBRBRBBBRR
4
RBBR

Sample Outputs:
Bob
Bob
Alice
Alice
Alice
Alice
Bob
Bob

Solution (Python):
sg = [0] * 1156
sg[0] = sg[1] = 0
vis = [False] * 1156
for i in range(2, 1156):
    for j in range(0, i - 1):
        vis[sg[j] ^ sg[i - j - 2]] = True
    for j in range(0, 1156):
        if not vis[j]:
            sg[i] = j
            break
    for j in range(0, i - 2):
        vis[sg[j] ^ sg[i - j - 2]] = False
for tc in range(int(input())):
    N = int(input())
    S = input()
    (R, B) = (S.count('R'), S.count('B'))
    if R > B:
        print('Alice')
        continue
    if R < B:
        print('Bob')
        continue
    (l, r, ans) = (0, 0, 0)
    while l < N:
        r = l + 1
        while r < N and S[r - 1] != S[r]:
            r += 1
        ans ^= sg[r - l] if r - l < 1156 else sg[1122 + (r - l) % 34]
        l = r
    print('Alice' if ans != 0 else 'Bob')

Solution (Python):
sg = [0] * 1156
sg[0] = sg[1] = 0
vis = [False] * 1156
for i in range(2, 1156):
    for j in range(0, i - 1):
        vis[sg[j] ^ sg[i - j - 2]] = True
    for j in range(0, 1156):
        if not vis[j]:
            sg[i] = j
            break
    for j in range(0, i - 2):
        vis[sg[j] ^ sg[i - j - 2]] = False
for tc in range(int(input())):
    N = int(input())
    S = input()
    (R, B) = (S.count('R'), S.count('B'))
    if R > B:
        print('Alice')
        continue
    if R < B:
        print('Bob')
        continue
    (l, r, ans) = (0, 0, 0)
    while l < N:
        r = l + 1
        while r < N and S[r - 1] != S[r]:
            r += 1
        ans ^= sg[r - l] if r - l < 1156 else sg[1122 + (r - l) % 34]
        l = r
    print('Alice' if ans != 0 else 'Bob')

Solution (Python):
import os
import sys
from io import BytesIO, IOBase
_str = str
str = lambda x=b'': x if type(x) is bytes else _str(x).encode()
BUFSIZE = 8192

class FastIO(IOBase):
    newlines = 0

    def __init__(self, file):
        self._fd = file.fileno()
        self.buffer = BytesIO()
        self.writable = 'x' in file.mode or 'r' not in file.mode
        self.write = self.buffer.write if self.writable else None

    def read(self):
        while True:
            b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
            if not b:
                break
            ptr = self.buffer.tell()
            (self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
        self.newlines = 0
        return self.buffer.read()

    def readline(self):
        while self.newlines == 0:
            b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
            self.newlines = b.count(b'\n') + (not b)
            ptr = self.buffer.tell()
            (self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
        self.newlines -= 1
        return self.buffer.readline()

    def flush(self):
        if self.writable:
            os.write(self._fd, self.buffer.getvalue())
            (self.buffer.truncate(0), self.buffer.seek(0))

class IOWrapper(IOBase):

    def __init__(self, file):
        self.buffer = FastIO(file)
        self.flush = self.buffer.flush
        self.writable = self.buffer.writable
        self.write = lambda s: self.buffer.write(s.encode('ascii'))
        self.read = lambda : self.buffer.read().decode('ascii')
        self.readline = lambda : self.buffer.readline().decode('ascii')
(sys.stdin, sys.stdout) = (IOWrapper(sys.stdin), IOWrapper(sys.stdout))
input = lambda : sys.stdin.readline().rstrip('\r\n')

def mex(a):
    for i in range(200):
        if i not in a:
            return i

def main():
    t = int(input())
    sg = [0] * 200
    for i in range(2, 200):
        a = set()
        for j in range(i - 1):
            a.add(sg[j] ^ sg[i - 2 - j])
        sg[i] = mex(a)
    while t:
        n = int(input())
        s = input()
        num = 0
        for i in range(n):
            if s[i] == 'R':
                num += 1
            else:
                num -= 1
        if num > 0:
            print('Alice')
        elif num < 0:
            print('Bob')
        else:
            i = 0
            res = 0
            while i < n:
                j = i
                while j < n - 1 and s[j] != s[j + 1]:
                    j += 1
                l = j - i + 1
                while l >= 200:
                    l -= 34
                res ^= sg[l]
                i = j + 1
            if res > 0:
                print('Alice')
            else:
                print('Bob')
        t -= 1
    return
main()