题解 P3727 【曼哈顿计划E】
will7101
·
·
题解
一句话题意:
一颗树上每个点有权值(SG函数值),问能否选择一条链,使SG函数值异或和为零。
预备知识
不会SG函数的同学请移步这里 -> ydc老师的博客
题解
直接放神犇同学@loveyayoi的题解:
n
k
-
通过打表可以发现一些规律
-
k=1时就是普通的nim游戏,sg(x)=x
-
k=2时通过打表可以发现明显的规律,如果s是偶数,sg函数有长度为s+1的循环节,值为0,1,0,1,0,1,0,1....,2,如果s是奇数,那么sg(x)=x\ mod\ 2
-
k=3时,打表也可以看出规律,sg(x)=\lfloor \frac{x}{s} \rfloor
- k=4时,打表得知,
$$sg(x)=
\begin{cases}
0 & \text{ , } x= 0 \\
x & \text{ , } x\equiv 1,2 (mod\ 4) \\
x+1 & \text{ , } x\equiv 3 (mod\ 4) \\
x-1 & \text{ , } x\equiv 0 (mod\ 4)
\end{cases}
## w
- w<=1000,暴力筛出sg函数即可
- w<=1e9,找规律O(1)求sg函数
## 复杂度
$O(T N log N)$,假设hash达到期望复杂度$O(1)$
代码:
```cpp
#include <bits/stdc++.h>
using namespace std;
const int MAXN=30005, MAXB=1e7;
char BUF[MAXB], *cp=BUF;
void rd(int &x){
x=0;
while(*cp<'0'||'9'<*cp) cp++;
while('0'<=*cp&&*cp<='9') x=x*10+*cp-'0', cp++;
}
int ne, hs, ok, nt, T, N, K, S;
int w[MAXN], sz[MAXN], vis[MAXN], tp[MAXN];
struct Edge{Edge *nxt; int to;}E[MAXN<<1], *hd[MAXN];
void adde(int u, int v){
E[ne].to=v; E[ne].nxt=hd[u]; hd[u]=&E[ne++];
E[ne].to=u; E[ne].nxt=hd[v]; hd[v]=&E[ne++];
}
int sg1(int x){return x;}
int sg2(int x){return (x+1)%(S+1)?x&1:2;}
int sg3(int x){return x/S;}
int sg4(int x){
switch(x%4){
case 0: return x-1;
case 3: return x+1;
default: return x;
}
}
void init(){
memset(hd,0,sizeof(hd)); ne=0;
memset(vis,0,sizeof(vis));
}
int gs(int u, int p){
sz[u]=1;
for(Edge *e=hd[u]; e; e=e->nxt){
int v=e->to;
if(v!=p&&!vis[v]) sz[u]+=gs(v,u);
}
return sz[u];
}
int gg(int u, int p){
for(Edge *e=hd[u]; e; e=e->nxt){
int v=e->to;
if(v!=p&&!vis[v]&&sz[v]>=hs) return gg(v,u);
}
return u;
}
int tt[MAXN];
void dfs(int u, int p, int s){
tt[nt]=u;tp[nt++]=s;
for(Edge *e=hd[u]; e; e=e->nxt){
int v=e->to;
if(v!=p&&!vis[v]) dfs(v,u,s^w[v]);
}
}
struct Hash{
static const int P1=100003, P2=100069;
inline int h1(int x){return x%P1;}
inline int h2(int x){return x%P2;}
int t1[P1], t2[P2], st[MAXN], top;
Hash(){
memset(t1,-1,sizeof(t1));
memset(t2,-1,sizeof(t2));
}
int find(int x){return t1[h1(x)]==x||t2[h2(x)]==x;}
void insert(int x){ if(find(x)) return;
int h=h2(x); st[top++]=x;
if(t2[h]==-1) t2[h]=x;
else while(~x){
h=h1(x); swap(x,t1[h]);
if(x==-1) return;
h=h2(x); swap(x,t2[h]);
}
}
void del(int x){
if(t1[h1(x)]==x) t1[h1(x)]=-1;
else t2[h2(x)]=-1;
}
void clear(){ while(top) del(st[--top]);}
}H;
void dc(int u){
hs=gs(u,0)>>1; int g=gg(u,0); vis[g]=1; H.insert(0);
for(Edge *e=hd[g]; e; e=e->nxt){
int v=e->to;
if(!vis[v]){
nt=0; dfs(v,0,w[v]);
for(int i=0; i<nt; ++i){
if(H.find(w[g]^tp[i])){ok=1;break;}
}
for(int i=0; i<nt; ++i) H.insert(tp[i]);
}
}
H.clear();
for(Edge *e=hd[g]; e&&!ok; e=e->nxt) if(!vis[e->to]) dc(e->to);
}
int main(){
fread(BUF, 1, MAXB, stdin);
rd(T);
while(T--){
init(); rd(N);
for(int i=1,u,v; i<N; ++i) rd(u),rd(v),adde(u,v);
for(int i=1; i<=N; ++i) rd(w[i]);
rd(K); int (*sg)(int);
if(K==1) sg=sg1;
else if(K==2) rd(S),sg=sg2;
else if(K==3) rd(S),sg=sg3;
else sg=sg4;
ok=0;
for(int i=1; i<=N; ++i) if(!(w[i]=sg(w[i]))) ok=1;
if(!ok) dc(1);
puts(ok?"Mutalisk ride face how to lose?":"The commentary cannot go on!");
}
return 0;
}
```