Niech $x$ oznacza liczbę pełnych pięter (na których są $3$ klocki, możemy wyciągnąć dowolny z tych trzech klocków), a $y$ - liczbę pięter, z których możemy wyciągnąć tylko jeden klocek (pojedyńczych pięter).
Stosując indukcję matematyczną po możliwych pozycjach wykażemy, że pozycje $x,y$ parzyste są przegrywające, a pozostałe są wygrywające.
Baza indukcji: pozycja $x=y=0$ jest przegrywająca, bo nie możemy wykonać żadnego ruchu.
Krok indukcyjny Najpierw przeprowadzamy indukcję po możliwych wartościach $y$ dla danego $x$, potem zwiększamy $x$, w ten sposób przechodzimy indukcją po wszystkich interesujących nas parach $x,y$. Rozważmy parę $x_1,y_1$ i załóżmy, że dla każdej pary $x_1>x$ albo $y_1>y$ (jeśli $x=x_1$) przegrywamy wtedy i tylko wtedy, gdy $x$ i $y$ są parzyste, a pozostałe pozycje są wygrywające.
Rozważmy kilka przypadków:
Użyjemy w tym celu programowania dynamicznego. Niech $dp[x][y]$ oznacza liczbę sposobów na otrzymanie pozycji $x,y$ modulo $10^9 + 7$. Dla początkowej pozycji $x,y$ $dp[x][y] = 1$. Podobnie jak w powyższym dowodzie, najpierw będziemy się iterować po coraz mniejszych $y$ dla danego $x$, a potem po coraz mniejszych $x$.
Policzenie rodzajów pięter pozwala nam na wyznaczenie zwycięzcy w czasie $O(1)$ i liczby możliwych notacji w $O(n^2)$, co dawało maksymalną liczbę punktów.
#include <bits/stdc++.h>
#define ll long long
using namespace std;
constexpr ll M = 1e9+7;
constexpr ll N = 5e3+7;
constexpr int debug = 0;
inline ll mod(ll a){
return ((a%M)+M)%M;
}
int main() {
ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
int n; cin >> n;
int p = 0, np = 0;
for(int i = 0; i < n; i++){
string ok;
for(int j = 0; j < 3; j++){
string a; cin >> a;
ok += a;
if(j < 2) ok += " ";
}
//if(debug) cout << ok << '\n';
if(i == 0) continue;
if(ok == "1 1 0" || ok == "0 1 1") np++;
else if(ok == "1 1 1") p++;
}
ll dp[p+3][np+p+3];
for(int i = 0; i < p+3; i++){
for(int j = 0; j < np+p+3; j++) dp[i][j] = 0;
}
(((p&1) == (np&1)) && ((np&1) == 0)) ? cout << "B\n" : cout << "A\n";
dp[p][np] = 1;
for(ll i = p; i >= 0; i--){
for(ll j = np+p; j >= 0; j--){
int a = (i&1), b = (j&1);
if(a == b){
if(a){
dp[i-1][j+1] = mod(dp[i-1][j+1] + dp[i][j]*2*i);
}
else{
if(i > 0){
dp[i-1][j] = mod(dp[i-1][j] + dp[i][j]*i);
dp[i-1][j+1] = mod(dp[i-1][j+1] + dp[i][j]*2*i);
}
if(j > 0){
dp[i][j-1] = mod(dp[i][j-1]+dp[i][j]*j);
}
}
}
else{
if(a){
dp[i-1][j] = mod(dp[i-1][j] + dp[i][j]*i);
}
else{
dp[i][j-1] = mod(dp[i][j-1] + dp[i][j]*j);
}
}
//if(debug) cout << "DEBUG " << i << ' ' << j << ' ' << dp[i][j] << '\n';
}
}
cout << dp[0][0] << '\n';
return 0;
}