[HNOI2014]江南乐题解

本文探讨了一位狂热的回合制玩家小A与对手在一种独特规则的江南游戏中的胜率计算。通过定义SG值并运用整除分块技巧,文章揭示了如何通过计算石子数量的奇偶性来预测先手与后手的胜负。核心算法优化了时间复杂度,帮助玩家在面对复杂游戏情境时做出决策。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

小A是一个名副其实的狂热的回合制游戏玩家。在获得了许多回合制游戏的世界级奖项之后,小A有一天突然想起了他小时候在江南玩过的一个回合制游戏。

游戏的规则是这样的,首先给定一个数F,然后游戏系统会产生T组游戏。每一组游戏包含N堆石子,小A和他的对手轮流操作。每次操作时,操作者先选定一个不小于2的正整数M (M是操作者自行选定的,而且每次操作时可不一样),然后将任意一堆数量不小于F的石子分成M堆,并且满足这M堆石子中石子数最多的一堆至多比石子数最少的一堆多1(即分的尽量平均,事实上按照这样的分石子万法,选定M和一堆石子后,它分出来的状态是固定的)。当一个玩家不能操作的时候,也就是当每一堆石子的数量都严格小于F时,他就输掉。(补充:先手从N堆石子中选择一堆数量不小于F的石子分成M堆后,此时共有N+M-1)堆石子,接下来小A从这N+M-1堆石子中选择一堆数量不小于F的石子,依此类推。

小A从小就是个有风度的男生,他邀请他的对手作为先手。小A现在想要知道,面对给定的一组游戏,而且他的对手也和他一样聪明绝顶的话,究竟谁能够获得胜利?

输入格式

输入第一行包含两个正整数T和F,分别表示游戏组数与给定的数。 接下来T行,每行第一个数N表示该组游戏初始状态下有多少堆石子。之后N个正整数,表示这N堆石子分别有多少个。

输出格式

输出一行,包含T个用空格隔开的0或1的数,其中0代表此时小A(后手)会胜利,而1代表小A的对手(先手)会胜利。

输入输出样例

输入 #1复制

4 3
1 1
1 2
1 3
1 5

输出 #1复制

0 0 1 1

说明/提示

对于100%的数据,T<100,N<100,F<100000,每堆石子数量<100000。

以上所有数均为正整数。

一次操作可以将一堆数量为 ii(i\ge Fi≥F)的石子分为 j-i\bmod jj−imodj 堆数量为 \left\lfloor\frac{i}{j}\right\rfloor⌊ji​⌋ 的石子和 i\bmod jimodj 堆数量为 \left\lceil\frac{i}{j}\right\rceil⌈ji​⌉ 的石子,其中 jj 是每次操作时玩家自行选定,满足 2\le j\le i2≤j≤i,FF 为给定。不能操作者输。

初始有 nn 堆石子,第 ii 堆石子的数量为 a_iai​。多组数据,但 FF 不改变。

T,n\le100T,n≤100,F,a_i\le10^5F,ai​≤105.

思路

我们定一个数的 \text{SG}SG 值为 f(x)f(x),一个局面的 \text{SG}SG 值为 f(state)=\bigoplus_{i\in state}f(i)f(state)=⨁i∈state​f(i)。

于是求出每个数的 \text{SG}SG 值即可。

首先,对于 i<Fi<F,f(i)=0f(i)=0,因为显然此时无法取到石子,先手必败。

然后枚举 jj,我们可以算出此时划分的局面的 \text{SG}SG 值。因为只有两种棋子的取值,且知道每堆的数量,所以算此时划分的局面的 \text{SG}SG 值是 O(1)O(1) 的。

令 v=\max\{a_i\}v=max{ai​},则此时时间复杂度为 O(v^2+Tn)O(v2+Tn),无法通过。

瓶颈在于计算 \text{SG}SG,我们观察式子,发现有 \left\lfloor\frac{i}{j}\right\rfloor⌊ji​⌋ 这一形式,于是考虑整除分块。

但是式子里还有 i\bmod jimodj 这一形态,整除分块不好处理,怎么办呢?

考虑向奇偶性方向想,

  • 当 2\nmid\left\lfloor\frac{i}{j}\right\rfloor2∤⌊ji​⌋ 时,j-i\bmod j=j-(i-j\left\lfloor\frac{i}{j}\right\rfloor)=j(1+\left\lfloor\frac{i}{j}\right\rfloor)-ij−imodj=j−(i−j⌊ji​⌋)=j(1+⌊ji​⌋)−i,发现此时 j-i\bmod jj−imodj 的奇偶性不变,则此部分贡献不变;
  • 当 2|\left\lfloor\frac{i}{j}\right\rfloor2∣⌊ji​⌋ 时,i\bmod j=i-j\left\lfloor\frac{i}{j}\right\rfloorimodj=i−j⌊ji​⌋,则 i\bmod jimodj 奇偶性不变,此部分贡献不变。

发现无论 \left\lfloor\frac{i}{j}\right\rfloor⌊ji​⌋ 的奇偶性,两种数量的石子的堆数中总有一种不变。

于是我们只需要枚举 22 个 jj 值就能代表所有情况了。

求 \text{mex}mex 可以暴力,因为集合里的数的个数为 O(\sqrt v)\times O(1)=O(\sqrt v)O(v​)×O(1)=O(v​)。

此时时间复杂度降为 O(v\sqrt v+Tn)O(vv​+Tn),可以通过。

由于查询的 a_iai​ 值较少,不会涵盖整个值域,可以使用记忆化搜索,比递推快很多。

代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
namespace IO{//by cyffff
	
}
const int N=1e5+10;
int n,T,f;
int SG[N];
inline int getSG(int i){
	if(i<f) return 0;
	if(~SG[i]) return SG[i];
	bool vis[100];
	memset(vis,0,sizeof(vis));
	for(int j=2,r;j<=i;j=r+1){
		r=i/(i/j);
		int res=0;
		bool flag=i%j;
		if(i%j&1) res^=getSG(i/j+1);
		if(j-i%j&1) res^=getSG(i/j);
		j++;
		vis[res]=i;
		if(flag){
			res=0;
			if(i%j&1) res^=getSG(i/j+1);
			if(j-i%j&1) res^=getSG(i/j);
			j++;
			vis[res]=i;
		}
	}
	for(int j=0;;j++)
		if(!vis[j])
			return SG[i]=j;
}
int main(){
	memset(SG,-1,sizeof(SG));
	T=read(),f=read();
	while(T--){
		n=read();
		int res=0;
		for(int i=1;i<=n;i++){
			res^=getSG(read());
		}
		write(res>0),putc(' ');
	} 
	flush();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值