2023.10.24

T1

题面

image

解题

  1. 判断先手与后手输赢的条件为 \(SG(a_i)\) 的异或和是否为 \(0\),问题转化为如何求 \(SG(x)\)
  2. 假设某堆石子的石子数量为 \(m=n^2+k,k\in \{0,1,\dots,2n\}\)。当 \(k\ne0\) 时,其后继状态的石子数均为 \(n^2-ln,l\in\{0,1,\dots,n\}\);当 \(k=0\) 时,其后继状态的石子数为 \(n^2-ln,l\in\{1,2,\dots,n\}\)。故只需要求得 \(SG(n^2),SG(n^2+1),n\in\{0,1,\dots,[\sqrt{\max\{a\}}]\}\)
  3. 因为每个待求的 \(SG(S)\) 的后继状态只有 \([\sqrt{S}]\) 个,故可通过记忆化搜索使得时间复杂度为 \(\mathcal O(max\{a\})\)
  4. 易错点:用 vector 取计算 mex 时,需要对其中元素进行去重(否则导致 \(SG\) 计算错误)。

代码

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+5;
int sg[maxn];
int f(int x)
{
	int y=(int)sqrt(x+0.5);
	int ex=y*y+(y*y==x?0:1);
	if(sg[ex]!=-1) return sg[x]=sg[ex];
	set<int> mex;
	int op=y*y-(y*y==ex?y:0);
	for(int i=op;i>=0;i-=y)
		mex.insert(f(i));
	set<int>::iterator it; int k=0;
	for(it=mex.begin();it!=mex.end();it++,k++)
		if(k!=*it) {sg[ex]=k;break;}
	if(sg[ex]==-1) sg[ex]=mex.size();
	return sg[x]=sg[ex];
}
signed main()
{
	memset(sg,-1,sizeof(sg));
	sg[0]=0;
	int n,ans=0;
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		int a; scanf("%d",&a);
		ans^=f(a);
	}
	if(ans==0) printf("Second\n");
	else printf("First\n");
	return 0;
}
posted @ 2023-10-25 01:42  shyiaw  阅读(64)  评论(0)    收藏  举报