最近做一些数学题目,感觉挺有意思的整理了一下。
北京理工大学2018级3月月赛A题:Ervin and Joker
传送门
简单博弈:不难看出,只要Ervin能把中间的一个或者两个拿走使之隔开,那么Ervin必胜。
所以有以下两种情况Ervin可能会输:
1 |
|
Codeforces Round #573 (Div. 2)D题:Tokitsukaze, CSL and Stone Game
传送门
写的时候被hack了,后来面向测试点的编程过了……
AC代码:
1 |
|
Codeforces Round #573 (Div. 2)E题:Tokitsukaze and Duel
题意:
给你一个长度为n的01字符串,和一个整数k。二人进行做博弈游戏,每个人必须选择一个连续的k个字符,把这连续的k个字符全变为0或者1。如果某次操作之后整个字符串全为1或者0,那么这个胜利,如果有无限多步要走,那么算平局,假设二人都绝顶聪明。给你初始局面,问游戏结果是什么?
思路:
首先应该明确,如果先手要赢,他一定要在第一步就赢,否则就不能再赢了。后手要赢的话,他要在他走的第一步赢,不然也不能再赢了、因为另外一个人可以重复选择他刚刚选择的区间,使其不停的翻转,可以知道这样是一直循环下去而且无意义的。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
using namespace std;
int main()
{
ll n,k,i=1,x=1,y=1,z;
cin>>n>>k;
string str;
cin>>str;
while(i<n && str[i]==str[0])
i++,x++;
i=n-2,z=n-k-1;
while(i>=0 && str[i]==str[n-1])
i--,y++;
if((x+k)>=n || (y+k)>=n || (str[0]==str[n-1] && (x+y+k)>=n))
cout<<"tokitsukaze"<<endl;
else if(str[0]!=str[n-1] && x>=z && y>=z && k>=z)
cout<<"quailty"<<endl;
else
cout<<"once again"<<endl;
return 0;
}
Educational Codeforces Round 68 (Rated for Div. 2)D. 1-2-K Game
题意:
当前在n位置,每一次可以向左走1,2,或者k步,最左的位置是0,不能走到0的左边, 二人博弈问题,谁没法再走的时候就输掉,问先手必赢还是后手必赢。
思路:
首先确定的是 0位置是必输位置,因为 1 2 和k这三个位置可以一步就走到0位置,所以这3个位置是必赢位置,以此规律,我们可以递推出sg函数。
由此我们可以打个表
1 |
|
不 难 发现:
- 如果k是3的倍数,那么sg函数是k+1长度的循环节,对循环节取模后,判断n是否是k,如果是k,那么k位置必赢,否则判断是否是3的倍数。如果k不是3的倍数,那么判断n是否是3的倍数即可。
AC代码:
1 |
|
POJ1082Calendar Game
题意:
给你一个年月日,你可以移动月和日,如果下个月没有当前的天数的时候你就不能移动月,当你刚好移动到11月4日你就赢了,如果你超过了十一月四日你就输了。
刚开始看这道题感觉可以用dfs,后来开始写代码时候感觉要判好几个条件,就没写下去,于是思考了一下,发现:
最终我们应该到达的是奇数点,即每次我们都需要保证自己走完后另一位所面对的是奇数局势,然后他只能走到偶数点,也就是一开始我们保证自己是偶数点开局就能赢。于是我就交了几发听取WA声。后来,参考了网上的题解。。
才知道,存在(9,30)这个点,下一个点还是奇数点(10,1),或者你可以直接走到(10,30),这样就是偶数点(聪明人都会选择前一种做法,让下一个人面对的局势是必败局),同样对于(11,30),你可以直接走到(12,1),这两个点也是必胜的。总结一下:只开局为偶数开局或者为(9,30),(11,30) 两个特殊的日子,就是必胜局,其他的为必败局。
AC代码:
1 |
|
博弈中诸如巴什博弈,威佐夫博奕,Fibonacci博弈,尼姆博弈,公平组合博弈(Impartial Combinatori Games),我觉得都挺有意思的,等过段时间我还想研究研究..