Kuangbin 博弈专题
文章目录
- Kuangbin 博弈专题
-
- HDU 1079 Calendar Game
- HDU 1525 Euclid's Game
- HDU 1564 Play a game
- HDU 1846 Brave Game
- HDU 1847 Good Luck in CET-4 Everybody!
- HDU 2516 取石子游戏
- HDU 2897 邂逅明下
- HDU 3032 Nim or not Nim?
- HDU 3389 Game
- HDU 3537 Daizhenyang's Coin
- HDU 3544 Alice's Game
- HDU 3863 No Gambling
- HDU 3951 Coin Game
- HDU 2188 悼念512汶川大地震遇难同胞――选拔志愿者
- HDU 2149 Public Sale
- HDU 1850 Being a Good Boy in Spring Festival
- HDU 2176 取(m堆)石子游戏
- HDU 1527 取石子游戏
- HDU 2177 取(2堆)石子游戏
- HDU 1517 A Multiplication Game
- HDU 2486 A simple stone game
- HDU 4315 Climbing the Hill
- HDU 1538 A Puzzle for Pirates
- HDU 3404 Switch lights
HDU 1079 Calendar Game
大意:
A和B两个人从一个日期开始,A先手,可以将这个日期变为下一天,或者是下个月中相同的天,有效的日期为1900年1月1日至2001年11月4日,无法取的人输,现在给出开始日期,问先手输赢
思路:
sg函数简单题,不过写日期写了好久…
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5;
typedef long long LL;
int t;
int f[150][15][35];
bool is_leap(int y) {
if (y % 4 == 0 && y % 100 != 0) return 1;
if (y % 400 == 0) return 1;
return 0;
}
bool check(int y, int m, int d) {
if (y > 2001) return 0;
if (y == 2001 && m > 11) return 0;
if (y == 2001 && m == 11 && d > 4) return 0;
if(m == 4 || m == 6 || m == 9 || m == 11){
if (d == 31) return 0;
}
if(m==2&&!is_leap(y)){
if (d == 29) return 0;
}
return 1;
}
int sg(int y, int m, int d) {
//cout << y << ' ' << m << ' ' << d << endl;
if (f[y - 1900][m][d] != -1) return f[y - 1900][m][d];
int ny, nm, nd;
//下一天
if (d == 31) {
nd = 1;
if (m == 12) {
nm = 1, ny = y + 1;
} else
ny = y, nm = m + 1;
} else if (d == 30) {
ny = y;
if (m == 4 || m == 6 || m == 9 || m == 11) {
nm = m + 1, nd = 1;
} else
nm = m, nd = d+1;
} else if (d == 29 && m == 2) {
ny = y, nm = 3, nd = 1;
}
else if(d==28&&m==2&&is_leap(y)){
ny = y, nm = 2, nd = 29;
}
else if(d==28&&m==2){
ny = y, nm = 3, nd = 1;
}
else{
ny = y, nm = m, nd = d + 1;
}
if(check(ny,nm,nd)){
if (sg(ny, nm, nd)==0) return f[y - 1900][m][d] = 1;
}
//下一月
if(m==12){
ny = y + 1, nm = 1, nd = 1;
}
else
ny = y, nm = m + 1, nd = d;
if(check(ny,nm,nd)){
if (sg(ny, nm, nd)==0) return f[y - 1900][m][d] = 1;
}
return f[y - 1900][m][d] = 0;
}
int main() {
cin >> t;
memset(f, -1, sizeof f);
f[2001 - 1900][11][4] = 0;
while (t--) {
int y, m, d;
cin >> y >> m >> d;
if (sg(y, m, d))
cout << "YES" << endl;
else
cout << "NO" << endl;
}
return 0;
}
HDU 1525 Euclid’s Game
大意:
有n和m两个数,每次可以从较大的那个数里取出较小的那个数的倍数,直到一个数变为0,不能取的人输,问先手是否必胜
思路:
非常玄妙,我愿称之为欧几里得博弈模型(doge)
dfs,假设当前两个数为a、b且a>=b,如果当前b==0,则必败,如果当前a % b ==0,则必胜,因为直接把a减到0即可
如果a大于b的两倍,那么也是必胜,因为此时:
如果b,a%b是必败态,先手将a,b变成b,a%b,那么先手肯定赢。
如果b,a%b是必胜态,先手将a,b变成b,a%b+b,那么对手只有将这两个数变成a%b,b,所以先手获胜。
而a在2b到b之间,那么只好直接dfs往下找,找到之后返回
#include <bits/stdc++.h>
using namespace std;
int c, a, b;
bool dfs(int a, int b) {
if (a < b) swap(a, b);
if (b == 0) return 0;
if (dfs(b, a % b) == 0 || a > b * 2)
return 1;
else
return 0;
}
int main() {
while (scanf("%d %d", &a, &b)&&(a+b!=0)) {
if (b > a) swap(a, b);
if (dfs(a, b))
printf("Stan wins\n");
else
printf("Ollie wins\n");
}
return 0;
}
HDU 1564 Play a game
大意:
一个nxn的棋盘,一个石头放在角落,轮流将这个石头移动到没有经过的位置,直到不能移动为止
思路:
猜结论+推理:一共有(n+1)^2个点,除去第一个点以外,如果有奇数个,那么一定是先手赢,因为走满了之后后手就走不了了,反之就是后手赢
#include<bits/stdc++.h>
using namespace std;
const int N = 1e4 + 5;
typedef long long LL;
LL n;
int main(){
while(scanf("%lld",&n)&&n!=0){
n++;
if(n*n%2==0){
cout << "ailyanlu" << endl;
}
else
cout << "8600" << endl;
}
return 0;
}
HDU 1846 Brave Game
巴什博弈裸题
#include <bits/stdc++.h>
using namespace std;
int main() {
int n, m, t;
cin >> t;
while (t--) {
cin >> n >> m;
if (n % (m + 1) == 0)
cout << "second" << endl;
else
cout << "first" << endl;
}
return 0;
}
HDU 1847 Good Luck in CET-4 Everybody!
给出n个石子,每次可以从中取出2的幂次,不能取的输
找规律结论:对3取模为0则先手必败(类