BZOJ 3895 3895: 取石子 / Luogu SP9934 ALICE - Alice and Bob (博弈 记忆化搜索)
转自PoPoQQQ大佬博客
题目大意:给定n堆石子,两人轮流操作,每个人可以合并两堆石子或拿走一个石子,不能操作者输,问是否先手必胜
直接想很难搞,我们不妨来考虑一个特殊情况
假设每堆石子的数量都>1
那么我们定义操作数b为当前石子总数+当前堆数-1
若b为奇数,则先手必胜,否则后手必胜
证明:
若当前只有一堆,则正确性显然
否则:
若b为奇数,那么先手只需进行一次合成操作,此时操作数会-1,且仍不存在大小为1的堆
因此只需要证明b为偶数时先手必败即可
若先手选择了合成操作,那么操作数-1且不存在大小为1的堆,状态回到了b为奇数的状态
若先手取走了某个大小>=3的堆中的一个石子,那么操作数-1且不存在大小为1的堆,状态回到了b为奇数的状态
若先手取走了某个大小为2的堆中的一个石子,那么后手只需要将另一个石子与其它堆合成,b的奇偶性不变且仍不存在大小为1的堆
故b为偶数时先手必败
现在回到一般情况 可能存在大小为1的堆
我们设有a个大小为1的堆,其余堆的操作数为b
那么当前的状态就可以用一个二元组(a,b)来表示
容易发现a<=50,b<=50049
于是枚举每种操作暴力记忆化搜索即可
CODE(BZOJ)
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 55;
const int MAXM = 50050;
int T, n, x;
char SG[MAXN][MAXM];
char ser(int a, int b) {
if(a == 0) return b&1;
//当不存在大小为1的堆时按照操作数计算必胜或必败
if(b == 1) return ser(a+1, 0);
//若操作数为1则此时b部分只有1个石子 划到a中
if(~SG[a][b]) return SG[a][b];
char &res = SG[a][b];
if(a && !ser(a-1, b)) return res = true;
//取走某个大小为1的堆中的石子
if(a && b && !ser(a-1, b+1)) return res = true;
//将某个大小为1的堆中的石子与某个大小不为1的堆合并
if(a > 1 && !ser(a-2, b+2+(b?1:0))) return res = true;
//将两个大小为1的堆中石子合并
if(b && !ser(a, b-1)) return res = true;
//对大小>1的堆进行合并或取走石子使操作数-1
return res = false;
}
int main () {
memset(SG, -1, sizeof SG);
scanf("%d", &T);
while(T--) {
scanf("%d", &n);
int A = 0, B = 0;
for(int i = 1; i <= n; ++i) {
scanf("%d", &x);
if(x == 1) ++A;
else B += x+(B?1:0);
}
puts(ser(A, B) ? "YES" : "NO");
}
}
CODE(Luogu)
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 55;
const int MAXM = 50050;
int T, n, x;
char SG[MAXN][MAXM];
char ser(int a, int b) {
if(a == 0) return b&1;
//当不存在大小为1的堆时按照操作数计算必胜或必败
if(b == 1) return ser(a+1, 0);
//若操作数为1则此时b部分只有1个石子 划到a中
if(~SG[a][b]) return SG[a][b];
char &res = SG[a][b];
if(a && !ser(a-1, b)) return res = true;
//取走某个大小为1的堆中的石子
if(a && b && !ser(a-1, b+1)) return res = true;
//将某个大小为1的堆中的石子与某个大小不为1的堆合并
if(a > 1 && !ser(a-2, b+2+(b?1:0))) return res = true;
//将两个大小为1的堆中石子合并
if(b && !ser(a, b-1)) return res = true;
//对大小>1的堆进行合并或取走石子使操作数-1
return res = false;
}
int main () {
memset(SG, -1, sizeof SG);
scanf("%d", &T); int kase = 0;
while(T--) {
scanf("%d", &n);
int A = 0, B = 0;
for(int i = 1; i <= n; ++i) {
scanf("%d", &x);
if(x == 1) ++A;
else B += x+(B?1:0);
}
printf("Case #%d: ", ++kase);
puts(ser(A, B) ? "Alice" : "Bob");
}
}
之所以用char存是因为只可能有-1/0/1三个值
还有对于b的其中某一堆石子可能从2取成1的情况的解释,见PoPoQQQ大佬博客评论区
BZOJ 3895 3895: 取石子 / Luogu SP9934 ALICE - Alice and Bob (博弈 记忆化搜索)的更多相关文章
- UVaLive 5760 Alice and Bob (博弈 + 记忆化搜索)
题意:有 n 堆石子,有两种操作,一种是从一堆中拿走一个,另一种是把两堆合并起来,Alice 先拿,谁不能拿了谁输,问谁胜. 析:某些堆石子数量为 1 是特殊,石子数量大于 1 个的都合并起来,再拿, ...
- HDU 4111 Alice and Bob (博弈+记忆化搜索)
题意:给定 n 堆石头,然后有两种操作,一种是把从任意一堆拿走一个,另一种是把一个石子放到另一堆上. 析:整体看,这个题真是不好做,dp[a][b] 表示有 a 堆1个石子,b个操作,操作是指把其他的 ...
- luogu P2657 [SCOI2009]windy数 数位dp 记忆化搜索
题目链接 luogu P2657 [SCOI2009]windy数 题解 我有了一种所有数位dp都能用记忆话搜索水的错觉 代码 #include<cstdio> #include<a ...
- bzoj 1668: [Usaco2006 Oct]Cow Pie Treasures 馅饼里的财富【记忆化搜索+剪枝】
c[x][y]为从(x,y)到(n,m)的最大值,记忆化一下 有个剪枝是因为y只能+1所以当n-x>m-y时就算x也一直+1也是走不到(n,m)的,直接返回0即可 #include<ios ...
- 【BZOJ-3895】取石子 记忆化搜索 + 博弈
3895: 取石子 Time Limit: 1 Sec Memory Limit: 512 MBSubmit: 263 Solved: 127[Submit][Status][Discuss] D ...
- bzoj3895: 取石子(博弈论,记忆化搜索)
3895: 取石子 Time Limit: 1 Sec Memory Limit: 512 MBSubmit: 361 Solved: 177[Submit][Status][Discuss] D ...
- 【BZOJ3895】取石子(博弈,记忆化搜索)
题意: Alice和Bob两个好朋含友又开始玩取石子了.游戏开始时,有N堆石子排成一排,然后他们轮流操作(Alice先手),每次操作时从下面的规则中任选一个:1:从某堆石子中取走一个2:合并任意两堆石 ...
- HDU.2516 取石子游戏 (博弈论 斐波那契博弈)
HDU.2516 取石子游戏 (博弈论 斐波那契博弈) 题意分析 简单的斐波那契博弈 博弈论快速入门 代码总览 #include <bits/stdc++.h> #define nmax ...
- 取石子游戏 HDU 1527 博弈论 威佐夫博弈
取石子游戏 HDU 1527 博弈论 威佐夫博弈 题意 有两堆石子,数量任意,可以不同.游戏开始由两个人轮流取石子.游戏规定,每次有两种不同的取法,一是可以在任意的一堆中取走任意多的石子:二是可以在两 ...
随机推荐
- JS实现级联菜单
是首先应该添加两个下拉列表并设置id属性来方便操作: <select id="country"> <option>国家</option> < ...
- notepad++一次多行复制粘贴到对应位置
NodePad++一次复制多行粘贴到对应位置 有时候要写sql,但是里面有很多字段要对应上,如果要自己一个字段一个字段的去写是在有点麻烦,是不是有更好的方法做到这件事呢? 要做这件事,首先分析下我们已 ...
- SQL0668N Operation not allowed for reason code "3" on table "TEST". SQLSTATE=57016
问题描述: 查询,操作表都报如下错误 SQL0668N Operation not allowed for reason code "3" on table "TEST ...
- HDU-6170 Two strings
http://acm.hdu.edu.cn/showproblem.php?pid=6170 . 匹配任意字符,x* 匹配任意长度的 x (x 为任意字符,长度可以为 0 ) 正则表达式 #inclu ...
- C++ STL String学习 (待续)
头文件:<string> 字符串类初始化: string s1="aabbba"; s2=string("bbb"); string s3=stri ...
- Pycharm 配置houdini
一.houdini开发环境配置 1.添加Python可执行文件 2.设置代码自动补全 刚刚添加的Python.exe,右侧点击加号,依次添加以上长方形中的文件,路径会根据个人安装路径有所变化,后面的目 ...
- Linux 多命令语句与重定向
多命令语句 Linux中我们在shell输入命令一般是一条一条执行,但是我们同样可以用一行语句写出多命令,下面就举出几个常见的方法 “;”分号用法 方式:command1 ; command2 用;号 ...
- How does a browser know which response belongs to which request?
Today I knows that the server never send a request to a client! It just make response~ So,if the bro ...
- codeforce B. Petya and Exam
wa一万次难受. #include<cstdio> #include<cstring> #include<cmath> #include<algorithm& ...
- python matplotlib 折线图
1.绘制折线图,去上和右边框,显示中文 import numpy as np import matplotlib.pyplot as plt #plt.style.use('default') #pl ...