小H玩游戏 (博弈+前缀和)

题目分析

这道博弈题目,判断当两人每次的都做出最有利于自身的策略时,谁将取得胜利?模拟样例,我们很容易发现,本次博弈最终的结果和操作顺序无关。

暴力思路:

将字符串从前往后进行遍历,遇到1就操作1次,将后面的数全部进行翻转,由于题目给的数据范围是,保证字符串的长度不大于100000。这种暴力思路时间复杂度太高(一般时间复杂度大于1e8就过不了了),要想办法优化一下。

差分前缀和:

因为结果与操作顺序无关,因此,我们不妨从前往后进行遍历。遇到1就将后面的数字进行翻转,更新序列的方法时间复杂度太高,我们可以使用数组进行优化,使用一个数组来记录每个位置的数字和操作次数,操作偶数次相当于没有操作,对结果无影响。

然后问题就转化为怎样求出操作次数。对于这样的场景,我们可以利用差分区间,对于每一个位置,如果是1,后面的数字都要反转,也就是后面的数字的操作次数加1,对应cnt[i]++,每次循环到一个新的位置时线计算前缀和(即当前位置的值),因为每次操作第一个可以保证第一个前面没有1,所以可以一边循环一边求差分数组的前缀和,时间复杂度线性

从前向后操作一遍,如果是奇数则Yes,否则No。

#include <bits/stdc++.h>
using namespace std;
const int N = 100010;
char s[N];
int cnt[N], sum[N];
int main()
{
    ios::sync_with_stdio(0); //加速读入的
    int n;
    cin >> n;
    while (n--){
        memset(cnt, 0, sizeof cnt);//初始化数组
        memset(sum, 0, sizeof sum);
        cin >> s;
        int len = strlen(s);
        int res = 0;
        if(s[0] == '1'){
            res++;      //操作数
            cnt[1]++;  
        }
        for (int i = 1; i < len; i++){
            sum[i] = sum[i - 1] + cnt[i];
            if(s[i] == '1' && sum[i] % 2 == 0){
                res++;
                cnt[i + 1]++;
            }
            else if(s[i] == '0' && sum[i] % 2 == 1){
                res++;
                cnt[i + 1]++;
            }
        }
        if(res & 1)cout << "Yes\n";
        else cout << "No\n";
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_60575429/article/details/129152249