F. Colouring Game(博弈论/sg函数)

题目
参考

题意

给定一个RB字符串序列。
Alice和Bob轮流操作,
Alice可以选择两个相邻的、至少有一个R字符的字符子串,并把它们染成白色;
Bob可以选择两个相邻的、至少有一个B字符的字符子串,并把它们染成白色。

最终哪方无路可走,则输了。
Alice和Bob都按最优思路去走。问最终谁是赢家。

思路

经典的博弈题,sg函数不太熟,感兴趣可以看看这篇介绍
sg函数介绍

直接套着公式就可以求解这道题了。
我们用W表示被染过的、白色的点。

对于R数量大于B数量的场景,Alice必赢。假如Bob去染RB,BR这两种状态的,则Alice也去染这种状态的;假如Bob去染WB,BW这两种状态的,则Alice也去染RW,WR这两种状态的。一直耗下去,最终由于R比B多出至少一个数量,Bob无路可走。

对于R数量小于B数量的场景,我们也可以做类似分析,此时Bob必胜。

对于R和B数量一致的场景,我们可以应用SG函数。
我们把原字符串划分为若干个、相邻字符不同的子字符串。
比如字符串RBRRBBBR,我们可以划分为RBR,RB,B,BR这几个子字符串。
则答案即为 S G ( R B R ) ⊕ S G ( R B ) ⊕ S G ( B ) ⊕ S G ( B R ) SG(RBR)\oplus SG(RB)\oplus SG(B)\oplus SG(BR) SG(RBR)SG(RB)SG(B)SG(BR)

至于不同长度的、相邻字符不同的字符串,它们的SG怎么求,就可以套SG公式了

sg(i)=mex(sg(i)^sg(i-j-2)),0<=j<=i-2

代码

#include<bits/stdc++.h>
using namespace std;
const int maxn = 500010;
//const int N=500005;
int n;
int sg[maxn], vis[maxn];
char s[maxn];
int f[maxn];
void init() {
	// sg函数初始化 
	for (int i = 1; i <= 100; ++i) {
		// sg[i] = mex(sg[j] ^ sg[i-j-2]) 
		for (int j = 0; j <= i - 2; ++j) {
			vis[sg[j]^sg[i-j-2]] = 1;
		}
		int j = 0;
		while (vis[j]) ++j;
		sg[i] = j;
		for (int j = 0; j <= i; ++j) {
			vis[j] = 0;
		}
	}
	/*
	for (int i = 1; i <= 500; ++i) {
		printf("%d ", sg[i]);
		if (i % 17 == 0) {
			printf("\n");
		}
	}*/
	// 打表可以发现 循环节是34 
	for (int i = 101; i < maxn; ++i) {
		sg[i] = sg[i-34];
	}
	
}

void solve() {
	scanf("%d", &n);
	scanf("%s", s);
	int res = 0;
	for (int i = 0; i < n; ++i) {
		char c = s[i];
		if (c == 'R') {
			++res;
		} else {
			--res;
		}
	}
	if (res != 0) {
		printf("%s\n", res > 0 ? "Alice" : "Bob");
		return;
	}
	
	int ans = 0;
	for (int i = 1, j; i <= n;) {
		j = i + 1;
		while (j <= n && s[j-1] != s[j-2]) {
			++j;
		}
		ans ^= sg[j-i];
		i = j;
	}
	printf("%s\n", ans ? "Alice" : "Bob");
}

int main() {
	init();
	int t; 
    scanf("%d", &t);
    while (t--) {
    	solve();
    }
}

最后

weixin gongzhonghao搜 对方正在debug,关注下,一起快乐刷题吧~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值