乒乒球
思考什么什么不写
题意
共记录了 \(n\) 颗球胜负关系,给出 \(n\) 和其长度为 \(k\) 的循环节,求最终比分。
思路
首先特判答案为 \(0:0\) 的情况:循环节与 AB
或 ABBA
同构。然后暴力找比分的周期,因为令任意位置作为一局起点时该局终点唯一,反之亦然,所以复杂度 \(O(\left| state \right|k)\)。
Code
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
signed main() {
cin.tie(0) -> sync_with_stdio(false);
ll n; int k; cin >> n >> k;
string s; cin >> s; s = ' ' + s;
auto ck = [&]() {
vector<int> v(k + 1);
for (int i = 1; i <= k; i++) v[i] = v[i - 1] + 2 * (s[i] == 'A') - 1;
return abs(v[1] - v[k]) == 1 && find(v.begin(), v.end(), 2) == v.end();
};
if (ck()) {
cout << "0:0" << '\n';
return 0;
}
vector<int> inv(k + 1);
auto P = [&](int i) {
return (i - 1) % k + 1;
};
array<unordered_map<int, int>, 2> C;
array<int, 2> c{0, 0};
int now = 1;
while (!inv[P(now)]) {
inv[P(now)] = now;
int a = 0, b = 0;
for (int j = now; ; j++) {
a += s[P(j)] == 'A';
b += s[P(j)] == 'B';
if (max(a, b) >= 11 && abs(a - b) >= 2) {
C[0][j] = (c[0] += a > b);
C[1][j] = (c[1] += b > a);
now = j + 1;
break;
}
}
}
int start = inv[P(now)];
int interval = now - start;
ll repeat = (n - start + 1) / interval;
ll patternCntA = (C[0][now - 1] - C[0][start - 1]) * repeat;
ll patternCntB = (C[1][now - 1] - C[1][start - 1]) * repeat;
int remain = start - 1 + (n - start + 1) % interval;
int remainCntA = 0, remainCntB = 0;
int a = 0, b = 0;
for (int i = 1; i <= remain; i++) {
a += s[P(i)] == 'A';
b += s[P(i)] == 'B';
if (max(a, b) >= 11 && abs(a - b) >= 2) {
remainCntA += a > b;
remainCntB += b > a;
a = b = 0;
}
}
cout << patternCntA + remainCntA << ':' << patternCntB + remainCntB << '\n';
return 0;
}