Lieges of Legendre CodeForces - 603C (博弈论,SG找规律)

大意: 给定$n$堆石子, 两人轮流操作, 每次操作两种选择

$(1)$任选非空堆拿走一个石子

$(2)$任选石子数为$2x(x>0)$的一堆, 替换为$k$堆$x$个石子. ($k$给定)

最后无法操作则输, 求谁能赢.

 

根据$SG$定理可以得到

$sg(x) =   \begin{cases} mex\{sg(x-1)\},&\text{$x$为奇} \\ mex\{sg(x-1),sg(\frac{x}{2})\},  & \text{$x$为偶且$k$为奇} \\ mex\{sg(x-1),0\}, & \text{$x$为偶且$k$为偶} \end{cases}$

然后找规律, 可以发现$k$为偶数时有循环节.

$k$为奇数时, $x$为较大的奇数一定必败, 那么就可以省去计算$sg(x-1)$, 只在偶数时计算$sg(\frac{x}{2})$, 这样单次计算$sg$复杂度就为$O(logx)$

#include <iostream>
#define REP(i,a,n) for(int i=a;i<=n;++i)
using namespace std;

int n, k;
const int f[]={0,1,0,1,2,0};

int solve(int x) {
	if (x<=5) return f[x];
	if (x&1) return 0;
	int t = solve(x/2);
	return t==1?2:1;
}

int sg(int x) {
	if (k%2==0)	{
		if (x==1) return 1;
		if (x==2) return 2;
		return x%2==0;
	}
	return solve(x);
}

int main() {
	scanf("%d%d", &n, &k);
	int ans = 0;
	REP(i,1,n) {
		int t;
		scanf("%d", &t);
		ans ^= sg(t);
	}
	puts(ans?"Kevin":"Nicky");
}

 

上一篇:博弈论总结


下一篇:2021-08-01