【BZOJ3609】[Heoi2014]人人尽说江南好【博弈】【打表找规律】

【题目链接】

没有子游戏,所以SG应该是用不上了。

然后来愉快的写暴力吧。

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int maxn = 1005;

int n, m, num[maxn];

inline bool check() {
	bool flag = 1;
	for(int i = 1; i < m; i++) for(int j = 1; j < m; j++) if(flag && ((i != j && i + j <= m && num[i] > 0 && num[j] > 0) || (i == j && i + j <= m && num[i] > 1)))
		flag = 0;
	return flag;
}

inline bool dfs() {
	if(check()) return 0;

	bool flag = 0;
	for(int i = 1; i < m; i++) for(int j = 1; j < m; j++) if(!flag && i + j <= m) {
		if(i == j) if(num[i] < 2) continue;
		if(i != j) if(num[i] < 1 || num[j] < 1) continue;
		num[i]--; num[j]--; num[i + j]++;
		if(!dfs()) flag = 1;
		num[i]++; num[j]++; num[i + j]--;
	}

	return flag;
}

int main() {
	printf("     ");
	for(int i = 1; i <= 20; i++) printf("%02d ", i);
	printf("\n");

	for(m = 1; m <= 20; m++) {
		printf("%02d :  ", m);
		for(n = 1; n <= 20; n++) if(n >= m) {
			memset(num, 0, sizeof(num));
			num[1] = n;
			printf("%d  ", dfs());
		}
		else printf("   ");
		printf("\n");
	}

	return 0;
}

这里1表示先手赢,0表示后手赢,与题目相反。
(下对角的规律非常明显,即(n, m),其中m > n,与(n, n)的值是一样的,所以不打出来)

打出来之后是这个样子:

     01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 
01 :  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  
02 :     1  1  0  0  1  1  0  0  1  1  0  0  1  1  0  0  1  1  0  
03 :        0  0  1  0  0  1  0  0  1  0  0  1  0  0  1  0  0  1  
04 :           1  1  0  1  0  0  1  0  1  1  0  1  0  0  1  0  1  
05 :              0  0  1  0  1  0  0  1  0  1  0  0  1  0  1  0  
06 :                 1  1  0  1  0  1  0  0  1  0  1  0  1  1  0  
07 :                    0  0  1  0  1  0  1  0  0  1  0  1  0  1  
08 :                       1  1  0  1  0  1  0  1  0  0  1  0  1  
09 :                          0  0  1  0  1  0  1  0  1  0  0  1  
10 :                             1  1  0  1  0  1  0  1  0  1  0  
11 :                                0  0  1  0  1  0  1  0  1  0  
12 :                                   1  1  0  1  0  1  0  1  0  
13 :                                      0  0  1  0  1  0  1  0  
14 :                                         1  1  0  1  0  1  0  
15 :                                            0  0  1  0  1  0  
16 :                                               1  1  0  1  0  
17 :                                                  0  0  1  0  
18 :                                                     1  1  0  
19 :                                                        0  0  
20 :                                                           1
从对角线上,按m分奇偶看。

当m为奇数时,循环节是这个样子,0 0 1 0 1 0 1 0 1 ... 一共有(m - 1) / 2个“01”,循环节长度为m。

当m为偶数时,循环节是这个样子,1 1 0 1 0 1 0 1 ... 0 0 1 0 1 0 1 0 ... ,前半段有m / 2 - 1个“01”,后半段是前半段的取反,循环节长度为2m。

然后写正解

/* Pigonometry */
#include <cstdio>
#include <algorithm>

using namespace std;

int n, m;

inline int iread() {
	int f = 1, x = 0; char ch = getchar();
	for(; ch < '0' || ch > '9'; ch = getchar()) f = ch == '-' ? -1 : 1;
	for(; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
	return f * x;
}

int main() {
	for(int T = iread(); T; T--) {
		n = iread(); m = iread();
		if(m > n) m = n;
		n -= m;
		if(m & 1) {
			n %= m;
			if(n == 0) printf("1\n");
			else {
				if(n & 1) printf("1\n");
				else printf("0\n");
			}
		} else {
			n %= 2 * m;
			if(n < m) {
				if(n < 2) printf("0\n");
				else {
					if(n & 1) printf("0\n");
					else printf("1\n");
				}
			} else {
				n -= m;
				if(n < 2) printf("1\n");
				else {
					if(n & 1) printf("1\n");
					else printf("0\n");
				}
			}
		}
	}
	return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值