hdu5724 博弈+SG函数+状压 多校1
2016-07-23 10:51
351 查看
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5724
题目大意:给你一个n*20的棋盘,棋盘上有一些棋子的位置,每次可以将棋子向右移动一格,有障碍的可以跳过,问先手必胜还是必败
思路:因为只有20列,所以可以预处理出所有状态的sg,每行的异或即可。
sg函数:
首先定义mex(minimal excludant)运算,这是施加于一个集合的运算,表示最小的不属于这个集合的非负整数。例如mex{0,1,2,4}=3、mex{2,3,5}=0、mex{}=0。
对于任意状态 x , 定义 SG(x) = mex(S),其中 S 是 x 后继状态的SG函数值的集合。如 x 有三个后继状态分别为 SG(a),SG(b),SG(c),那么SG(x) = mex{SG(a),SG(b),SG(c)}。 这样 集合S 的终态必然是空集,所以SG函数的终态为 SG(x) = 0,当且仅当 x 为必败点P时。
棋盘的sg用状压搞一下,每次判断当前位置的棋子可以移动到哪些位置,然后记录即可。。。。具体看代码
题目大意:给你一个n*20的棋盘,棋盘上有一些棋子的位置,每次可以将棋子向右移动一格,有障碍的可以跳过,问先手必胜还是必败
思路:因为只有20列,所以可以预处理出所有状态的sg,每行的异或即可。
sg函数:
首先定义mex(minimal excludant)运算,这是施加于一个集合的运算,表示最小的不属于这个集合的非负整数。例如mex{0,1,2,4}=3、mex{2,3,5}=0、mex{}=0。
对于任意状态 x , 定义 SG(x) = mex(S),其中 S 是 x 后继状态的SG函数值的集合。如 x 有三个后继状态分别为 SG(a),SG(b),SG(c),那么SG(x) = mex{SG(a),SG(b),SG(c)}。 这样 集合S 的终态必然是空集,所以SG函数的终态为 SG(x) = 0,当且仅当 x 为必败点P时。
棋盘的sg用状压搞一下,每次判断当前位置的棋子可以移动到哪些位置,然后记录即可。。。。具体看代码
#include <iostream> #include <cstdio> #include <string> #include <cstring> #include <cmath> #include <stack> #include <queue> #include <algorithm> #include <vector> #include <map> #include <set> #include <stdlib.h> #include <iomanip> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define maxn 1500005 #define MOD 1000000007 #define mem(a , b) memset(a , b , sizeof(a)) #define LL long long #define ULL unsigned long long #define FOR(i , n) for(int i = 1 ; i<= n ; i ++) typedef pair<int , int> pii; int t , n , q , a[maxn][20]; int sg[maxn]; int get_sg(int x) { int vis[20]; mem(vis , 0); for(int i = 19 ; i >= 0 ; i --) { if(x & (1 << i)) //第i列有棋子 { int y = x; for(int j = i - 1; j >= 0 ; j --) { if(!((1 << j) & x)) //第j列没棋子,将第i列的棋子移到第j列,得到新的状态 { y = y ^ (1 << i) ^ (1 << j); break; } } if(y == x) continue; vis[sg[y]] = 1; } } for(int i = 0 ; i <= 19 ; i ++) if(!vis[i]) return i; } int main() { for(int i = 0 ; i < (1 << 20) ; i ++) sg[i] = get_sg(i); scanf("%d" , &t); while(t --) { scanf("%d" , &n); int ans = 0 , tmp , num; for(int i = 0 ; i < n ; i ++) { scanf("%d" , &tmp); int ss = 0; while(tmp--) { scanf("%d" , &num); ss |= (1 << ( 20 - num)); } ans ^= sg[ss]; } if(!ans) printf("NO\n"); else printf("YES\n"); } return 0; }
相关文章推荐
- PhpStorm中报 “Cannot run program git.exe, 系统找不到指定的文件” 错误的解决方法
- 零配置文件搭建SpringMVC实践纪录
- Git的基本了解与使用、向github提交代码
- Hibernate学习笔记----映射继承关系
- hdu 5739 Fantasia (2016多校第二场1006)
- 几种排序算法比较
- DFS-Prime Ring Problem
- 关于favicon.ico
- 前端基本功—CSS 实战第一天
- linux的x window system
- 【Android】友盟社会化分享
- 318. Maximum Product of Word Lengths
- LoadRunner 技巧之 IP欺骗 (推荐)
- 正则表达式
- tjut 4902
- PHP二维数组去重
- 30行代码实现JavaScript中的MVC
- Java 输入一个大写字母,如 F,输出 比如: 输入:F 输出: F EFE DEFED CDEFEDC BCDEFEDCB ABCDEFEDCBA
- scala parse使用记录
- Java——反射