【倍增】Rigged Games

题意

两队打比赛,大比分 2b − 1 赢,小比分 2a − 1 赢。
给定的长度为 n 的串,两队比赛的每个小分结果是这个串的循环重复。
问从该串的每个位置开始,最终谁会赢得整个比赛。

思路

倍增。

首先对于每个位置,计算出它 \(2a-1\) 局后的比分的比分终点的位置。

然后采用倍增,即假设我们要从 \(j\)\(2^i\) 步,可以先从 \(j\)\(2^{i-1}\) 步,然后从跳 \(2^{i-1}\) 的终点也就是 \(jump_{2^{i-1},j}\) 再跳 \(2^{i-1}\) 步,即 \(jump_{i,j} = jump_{i-1,jump_{i-1},j}\)

同理,从 \(j\)\(2^i\) 步的得分我们也要累计起来,但这个时候要统计两部分的 a 小局比分,即 \(j\sim j+2^{i-1}\)\(j+2^{i-1}\sim j+2^i\) 的。

最终判断的时候每次从 \(2^{17}\) 往后跳到凑出 \(2b-1\) 的比分即可。(\(2^{17}>1e5\))

代码

#include <bits/stdc++.h>

using namespace std;

using i64 = long long;

int main() {
   ios::sync_with_stdio(false);
   cin.tie(nullptr);

   int n, a, b;
   cin >> n >> a >> b;

   vector jump(18, vector<int>(n));
   vector sum(18, vector<int>(n));

   string s;
   cin >> s;

   int sc[2] {}, r = 0;
   for (int i = 0; i < n; i ++) {
      while (sc[1] < a && sc[0] < a) {
         sc[s[r] - '0']++;
         r = (r + 1) % n;
      }
      jump[0][i] = r;
      sum[0][i] = sc[1] > sc[0];
      sc[s[i] - '0']--;
   }

   for (int i = 1; i < 18; i ++) {
      for (int j = 0; j < n; j ++) {
         jump[i][j] = jump[i - 1][jump[i - 1][j]];
         sum[i][j] = sum[i - 1][j] + sum[i - 1][jump[i - 1][j]];
      }
   }

   int pos, res, ans;
   for (int i = 0; i < n; i ++) {
      pos = i, res = 0, ans = 0;
      for (int j = 17; j >= 0; j --) {
         if (res + (1 << j) <= 2 * b - 1) {
            res += 1 << j;
            ans += sum[j][pos];
            pos = jump[j][pos];
         }
      }
      cout << (ans >= b);
   }

   return 0;
}
posted @ 2024-08-12 20:00  Ke_scholar  阅读(6)  评论(0编辑  收藏  举报