【博弈论】B1. Palindrome Game (easy version)—— Codeforces Round #721 (Div. 2)

本文探讨了一种字符串填充问题,涉及到博弈论的策略。问题分为简单和复杂两种情况,分析了Alice和Bob两位玩家如何在填充0和1以形成回文串的过程中取得优势。在简单的场景中,当字符串中0的数量为偶数时,Bob可以通过特定策略确保平局;而在复杂场景中,考虑了中间0和不对称0的情况,进一步分析了胜利条件。文章通过代码示例解释了不同策略和状态转移,并给出了判断胜利方的算法实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本题有难易两个版本。

easy version:
https://codeforces.com/contest/1527/problem/B1

/*
当0, B,差1
当00,B,差2
当000,A,中间多1,但最后少2
对于00,A1B1可以
讨论:
eke——只有中间一个0的时候,bob赢。0个数是偶数时,alice每次放一个,bob就放对称,最后一对0,alice填了一个给bob的时候bob不放,这样bob总是比alice少填2个
为奇数的时候,alice填中间那个,把偶数的时候alice面对的状态转移给bob,这样alice总是比bob少填2-1个
b2应该是先让bob把所有非回文的地方补上,昨天晚上太混乱了
灵儿——哦意思就是博弈论能赢就行,不是贪心解法…
我想0个数是偶数时,alice每次放一个,bob就翻一下,alice再放一个对称,bob变成了alice,就乱七八糟的混乱w
其实不面对对称的优势值2分,这样就够了w之后像nim一样在平手情况下,维持这样的优势,躺赢
*/

小错误:
//这里小输入符错!
//注意初始化!

#include<bits/stdc++.h>
#ifdef LOCAL
FILE*FP=freopen("text.in","r",stdin);
#endif
using namespace std;

char str[1003];
void get(int&a,int&b,int&n){
	scanf("%d",&n);
	scanf("%s",str);//这里小输入符错! 
	a=0,b=0;//注意初始化! 
	for(int i=0;i<n/2;i++){
//		printf("%c %c\n",str[i],str[n-i-1]);
		if(str[i]=='0'&&str[n-i-1]=='0')a++;
	}
	if(n%2&&str[n/2]=='0')b++;
//	printf("in:%d %d %d\n",a,b,n);
}
signed main(){
	int t,n,a,b;//对称,中间 
	scanf("%d",&t);
	int flag=0;//1a2b
	while(t--){
		get(a,b,n);
//		printf("%d %d %d\n",a,b,n);
		if(b==0||a==0)flag=2;
		else flag=1;
		printf("%s\n",(flag==1)?"ALICE":"BOB");
	}
	return 0;
}

hard version:
有之前的经验,多讨论一下
从A先手希望取胜的方面讨论,首先先手有优势的话保持就是了,这就是关键,从先手的角度看策略。

如何保持先手优势,减小问题规模:

对称00

A只能填一个,B填另一个,不变,平手
谁能让对手处在对称00,其实是占优的
因为A只能填一个,B也可以翻转,则A,-2,而让对方处于这个情况对调了,其实还是A想这样化回来,B被动就有被平手的可能。所以B选择走最小的步长,掌控时机让A-2时刚好下完
——后手胜,-2

不对称0011

A翻转,B填,不变,A+1
——先手胜,+m

有中0:

只有中0:

A只能取之,-1,负

此外只有对称0:

A取中0,-1,之后可保证+2,整体+1,所以必胜

此外只有m个不对称0:

A不要白不要(理解一下不要是不是白不要了)
所以让B填m个,+m,之后自己来填最后一个,-1,最少了,整体m-1
m=1,平,m>1,胜

有对称0和不对称0:

A先白要m个,+m,并且还是到了此外只有对称0,能必胜

无中0:

只有对称0:

即对称00情况
——A负

只有不对称0:

即不对称0011情况
——A胜

有对称0和不对称0:

A要先享受不对称0优势,B填也不会去填对称0创造更多不对称0,A有m-1分
之后A填了最后的不对称0,把对称00局面给了B,A有2分
——整体m-1分,A胜

下结论

为了最后判断,按胜负总结,不是去一个个寻找那么多情况是不是匹配

A负:

1.只有中间0
2.只有对称0

A平:

1.只有(中间0和一个不对称0)

A胜:

1.有中0,有对称0
2.有中0,有多于一个不对称0
3.无中0,有不对称0

#include<bits/stdc++.h>
#ifdef LOCAL
FILE*FP=freopen("text.in","r",stdin);
#endif
using namespace std;
char str[1003];
void get(int&f1,int&f2,int&f3,int&n){
	f1=f2=f3=n=0; 
	scanf("%d",&n);
	scanf("%s",str);
	if(n%2&&str[n/2]=='0')f1=1;//有中0 
	for(int i=0;i<n/2;i++){
		//printf("%c %c\n",str[i],str[n-i-1]);
		if(str[i]=='0'&&str[n-i-1]=='0')f2++;//对称0 
		if(str[i]!=str[n-i-1])f3++;
	}
	//printf("in:%d %d %d\n",f1,f2,f3);
}
signed main(){
	int t,n,f1,f2,f3,f;//中间, 对称, 不对称 //f:a1胜2负3平 
	scanf("%d",&t);
	while(t--){
		get(f1,f2,f3,n);
		//printf("%d %d %d\n",f1,f2,f3);
		if((f1&&!f2&&!f3)||(f2&&!f1&&!f3))f=2;
		else if(f1&&f3==1&&!f2)f=3;
		else f=1;
		if(f==1)printf("ALICE\n");
		if(f==2)printf("BOB\n");
		if(f==3)printf("DRAW\n");
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值