AT3727 [ARC087C] Prefix-free Game 题解

Description.

如果两个字符串互不为前缀,那就定义它们是好的对。
一个字符串集是好的,当且仅当:

  • 字符串集中的所有元素两两都是好的
  • 字符集中所有元素都是由 01 构成的
  • 字符集中所有元素长度都 \(\le L(L\le 10^{18})\)

Alice 和 Bob 打隔膜,每次他们可以加入一个字符串,需要满足插入后集合还是好的。
谁不能插入了谁是人输,问谁是人赢。
保证初始字符串集的长度和 \(\le 10^5\)

Solution.

首先建出 01Trie
然后相当于这个 Trie 上的所有节点都不能选择了。
这个 Trie 距离 满Trie 差的点都是可以选择的。
选择一个点后它所有祖先都和所有后代都不能选择。
手模样例后发现,我们需要考虑的就是很多棵小 满Trie,它们之间互不干扰。
看到互不干扰,就想到可以用 SG函数 来解决这个问题。
我们只需要考虑一棵深度为 \(L(L\le 10^{18})\)满TrieSG函数 ,再全部 \(\oplus\) 起来即可。
设一棵深度为 \(x\)满trieSG函数\(SG_x\)

\[SG_x=\begin{cases} 0&x=0\\ \text{mex}_{i=1}^x\left({\bigoplus_{j=i}^{x-1}SG_j}\right)&x>0 \end{cases} \]

因为 \(x\le L\le 10^{18}\),所以递推肯定不可能,必须要 \(O(1)\)\(O(\log N)\) 算。
打表发现,\(SG_i=\text{lowbit}(i)\),然后就可以 \(O(1)\) 计算 \(SG_x\) 了。
同时,插入一个长度为 \(n\) 的字符串最多会产生 \(n+1\) 个满二叉树,所以满二叉树总数量是 \(O(n)\) 级别的。
然后这题就做完了。

Coding.

点击查看一个巨弱的代码
//是啊,你就是那只鬼了,所以被你碰到以后,就轮到我变成鬼了{{{
#include<bits/stdc++.h>
using namespace std;typedef long long ll;
template<typename T>inline void read(T &x)
{
	x=0;char c=getchar(),f=0;
	for(;c<48||c>57;c=getchar()) if(!(c^45)) f=1;
	for(;c>=48&&c<=57;c=getchar()) x=(x<<1)+(x<<3)+(c^48);
	f?x=-x:x;
}/*}}}*/
int n,ch[2000005][2],d[2000005],tt,rt;char s[100005];ll L;
inline void ins(int &x,char *s,int dep,int lim)
{
	d[x?x:x=++tt]=dep-1;if(dep==lim+1) return;
	ins(ch[x][s[dep]-'0'],s,dep+1,lim);
}
inline ll sg(ll x) {return x&(-x);}
inline ll dfs(int x) {return (ch[x][0]?dfs(ch[x][0]):sg(L-d[x]))^(ch[x][1]?dfs(ch[x][1]):sg(L-d[x]));}
int main()
{
	read(n),read(L);for(int i=1;i<=n;i++) scanf("%s",s+1),ins(rt,s,1,strlen(s+1));
	return puts(dfs(rt)?"Alice":"Bob"),0;
}
posted @ 2021-07-25 11:56  Peal_Frog  阅读(58)  评论(0编辑  收藏  举报