题目分析
这道博弈题目,判断当两人每次的都做出最有利于自身的策略时,谁将取得胜利?模拟样例,我们很容易发现,本次博弈最终的结果和操作顺序无关。
暴力思路:
将字符串从前往后进行遍历,遇到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;
}