Rigged Games (牛客多校3 J)

进入博客阅读体验更佳:[Rigged Games (牛客多校3 J) | 付诺の小站 (https://funuo0728.github.io/2024/07/26/Rigged-Games-%E7%89%9B%E5%AE%A2%E5%A4%9A%E6%A0%A13-J/)

Rigged Games

题目大意


给定一个长度为 n ( 1 ≤ n ≤ 1 0 5 ) n(1 \le n \le 10^5) n(1n105) 01 01 01字符串以及两个整数 a a a b ( 1 ≤ a , b ≤ 1 0 5 ) b(1 \le a, b \le 10 ^ 5) b(1a,b105) 1 1 1表示这一小局 t e a m   A team \ A team A获胜, 0 0 0则表示 t e a m   B team \ B team B获胜。当一个 t e a m team team获胜 a a a小局后,记作获胜一大局,并将小局比分清空。获胜 b b b大局后则赢得最终胜利。问将这个字符串以第 i ( 1 ≤ i ≤ n ) i(1 \le i \le n) i(1in)位作为起点开始循环时,最终获胜的队伍是不是 t e a m team team,若是输出 1 1 1,否则输出 0 0 0

解题思路


考虑对于每个起点 i i i预处理出从这个点开始完成一大局比赛后第二局比赛的起点,以及这一大局 t e a m   A team\ A team A是否获胜。自然想到再用倍增预处理出进行 2 1 , 2 2 , 2 3 , … 2 ^ 1,2^2,2^3,\dots 21,22,23,大局后 t e a m   A team\ A team A获胜的次数。然后处理询问,只需要从最高位往下遍历凑出有一个队获胜的条件即可。至于预处理大局的起点,可以联想到双指针,因为每一小局在 1 1 1~ n n n上是连续的。

最后将上面的想法整理起来即可。

参考代码

#include <bits/stdc++.h>
#define maxn 100100
#define int long long
using namespace std;
const double eps = 1e-8;
int f[maxn][22], sum[maxn][22];

void solve() {
    int n, a, b;
    cin >> n >> a >> b;
    string s;  cin >> s;
    int cnta = 0, cntb = 0;
    for (int i = 0, j = 0; i < n; ++i) {
        while(cnta < a && cntb < a) {
            if(s[j] == '0')  cntb++;
            else  cnta++;
            j = (j + 1) % n;
        }
        f[i][0] = j;
        sum[i][0] = (cnta > cntb);
        if(s[i] == '0')  cntb--;
        else  cnta--;
        // cout << sum[i][0] << ' ' << f[i][0] << '\n';
    }
    for (int j = 1; j < 20; ++j) {
        for (int i = 0; i < n; ++i) {
            sum[i][j] = sum[i][j - 1] + sum[f[i][j - 1]][j - 1];
            f[i][j] = f[f[i][j - 1]][j - 1];
        }
    }
    for (int i = 0; i < n; ++i) {
        int cur = 0, pos = i;
        cnta = 0, cntb = 0;
        for (int j = 19; j >= 0 && cnta < b && cntb < b; --j) {
            if(cur + (1 << j) > 2 * b - 1)  continue;
            if(cnta + sum[pos][j] > b)  continue;
            if(cntb + (1 << j) - sum[pos][j] > b)  continue;
            cnta += sum[pos][j];  cntb += (1 << j) - sum[pos][j];
            cur += (1 << j);  pos = f[pos][j];
        }
        // cout << cnta << ' ' << cntb << '\n';
        if(cnta == b)  cout << 1;
        else  cout << 0;
    }
}

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(0);  cout.tie(0);
    int t = 1;
    while (t--) {
        solve();
    }
    return 0;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值