专栏文章

题解:P7966 [COCI 2021/2022 #2] Hiperkocka

P7966题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@mioxrm2y
此快照首次捕获于
2025/12/03 02:53
3 个月前
此快照最后确认于
2025/12/03 02:53
3 个月前
查看原文
首先相信大家都发现了得满分要求每条边都被选入某棵树。
从菊花入手,此时等价于选出 2n12^{n-1} 个数使得他们两两之间相差至少两个二进制位。只需要选出所有 popcount\mathrm{popcount} 为偶数的数即可。
再考虑一般情况,换个角度理解题意,就是对于每条边 (x,y)(x,y) 能找出它是哪棵树的哪条边。
尝试将这个定位逻辑简单化,那么由 xxyy 得出的一个简单信息是 xxyy 在哪一位不同,设为 ii,那么我们可以规定它被定位到某棵树的第 ii 条边上。
这也就是给 TT 的每条边赋一个互不相同的 00n1n-1 的边权(顺序随意),要求结果中每个 TT 的相邻两点间相差的位就是边上的边权,即对于每个 1i2n11\le i\le 2^{n-1}u,v,(u,v)T:ai,uai,v=2e(u,v)\forall u,v,(u,v)\in T: a_{i,u}\oplus a_{i,v}=2^{e_(u,v)},其中 ee 为所赋的边权。
于是此时我们只用确定 ai,0a_{i,0} 整个 aia_i 序列就确定了。只需考虑怎么给每个 ai,0a_{i,0} 赋值。
考虑什么时候两棵树的两条边会冲突。
那么若 T1T_1T2T_2 都含有边 (x,y)(x,y),则 (x,y)(x,y)T1T_1T2T_2 的边权必然相同(为 log2(xy)\log_2(x\oplus y)),也即它们是 TT 上的同一条边。
我们将树按从根向叶子的方向定向,则若 (x,y)(x,y)T1T_1T2T_2 中的方向相同,可以倒推出 T1T_1T2T_2 的根节点权值相同,矛盾。
因此只有当 (x,y)(x,y)T1T_1 中是 xyx\rightarrow y 而在 T2T_2 中是 yxy\rightarrow x 时有可能冲突,此时可以推出 T1T_1T2T_2 的根节点的权值恰相差一个二进制位 e(x,y)e_{(x,y)}
rt1c1 c2cmxe(x,y)y cmc2 c1rt2rt_1 \xrightarrow{c_1} \ \xrightarrow{c_2} \dots \xrightarrow{c_m} x \xleftrightarrow{e_{(x,y)}} y \ \xleftarrow{c_m} \dots \xleftarrow{c_2} \ \xleftarrow{c_1} rt_2
于是沿用菊花的做法,令每个根的节点都是 popcount\mathrm{popcount} 为偶数的数即可。
代码 500B。
CPP
#include <bits/stdc++.h>
#define For(i,a,b) for(int i=a;i<=b;i++)
#define Rev(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
constexpr int N=55;
int n,a[N],cnt; vector<int> to[N];
void dfs(int u,int pa) { for(int v:to[u]) if(v!=pa) a[v]=a[u]^(1<<(cnt++)), dfs(v,u); }
int main(){
    cin>>n; For(i,1,n) { int x,y; cin>>x>>y; to[x].push_back(y); to[y].push_back(x); }
    dfs(0,-1); cout<<(1<<(n-1))<<'\n';
    For(s,0,(1<<n)-1) if(__builtin_parity(s)) For(i,0,n) cout<<(s^a[i])<<" \n"[i==n];
    return 0;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...