• CF1543E The Final Pursuit 题解


    Codeforces
    Luogu

    Description.

    定义一张图是 \(n\) 完美图当且仅当:

    • \(2^n(n\in\mathbb N)\) 个点和 \(n\times 2^{n-1}\) 条边
    • \(\forall x,y\)\(x\)\(y\) 有边当且仅当 \(x\oplus y=2^k(k\in\mathbb N)\)

    定义一张图是 \(n\) 好图当且仅当:

    • 它可以通过一 \(n\) 完美图通过点置换得到

    一个 \(k\) 染色方案是合法的当且仅当:

    • 染色在 \(n\) 进行,染了 \(n\) 种颜色分别为 \(\{0,1,...,n-1\}\)
    • 对于一个点,和它相邻的所有点颜色有 \(n\) 种不同的取值

    给定一张好的图,请构造一个点置换,并构造一种合法的染色方案,如果无解输出 -1

    Solution.

    \(n\) 完美图是唯一的,且第 \(i\) 号点和 \(i^(2^k)\) 对称,这点根据定义可得。
    \(\because k\in[0,n)\),所以图上任意两个点都对称。
    所以我们可以任意钦定一个点为完美图上的 \(0\) 号点。
    同时,我们发现了一个性质,按照 \(\text{bit}(x)\) 的个数来分层,完美图是一个分层图。
    那就钦定一个点为第 \(0\) 层,然后钦定第一层的全是 \(\{2^k\}\),然后下一层的就等于上一层所有向他连边数的 \(\text{or}\)
    然后第一问就构造完了,而且可以证明正确性。

    考虑第二问,每个点总共就 \(n\) 条出边,而且分别 \(\oplus 2^i(i\in[0,n))\)
    考虑第一种颜色出现次数,它在每个节点周围出现了一次,总计 \(2^n\) 次。
    然后每个颜色为 \(1\) 的节点,它周围有 \(n\) 个点,所以它被算重了 \(n\) 次。
    所以真正出现次数是 \(\frac{2^n}{n}\),这必定是一个整数。
    我们证明了在 \(n\) 不为 \(2^k(k\in\mathbb N\) 的情况下必定无解。

    首先考虑 \(0\) 号点,那我们可以钦定第 \(2^i\) 号点颜色是 \(i\)
    同时,考虑一个性质,一个长度为 \(2^k\) 的排列 \(\oplus x(x\in[0,2^k))\) 后仍然是个排列,证明显然。
    所以我们可以对于一个数字,它所有拥有的位取 \(\oplus\),可以证明这个构造方式一定是正确的。
    \(n=2^k\),那相当于它周围的所有点是 \(a_x\oplus y\ (y\in[0,2^k))\),根据上面的性质,必然是一个排列。
    所以正确性得证。

    然后这题就做完了。

    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;
    }/*}}}*/
    const int N=65537;int n,m,lim,iv[N],rs[N];char v[N];
    struct edge{int to,nxt;}e[N<<4];int et,head[N];
    inline void adde(int x,int y) {e[++et]=(edge){y,head[x]},head[x]=et;}
    inline void solve()
    {
    	read(n),m=n*(1<<(n-1)),lim=1<<n,et=0;for(int i=0;i<lim;i++) head[i]=iv[i]=v[i]=0;
    	for(int i=0,x,y;i<m;i++) read(x),read(y),adde(x,y),adde(y,x);
    	vector<int>ls,nw;iv[0]=0,v[0]=1;int cnt=1;
    	for(int i=head[0],j=0;i;i=e[i].nxt,j++)
    		iv[e[i].to]=1<<j,ls.push_back(e[i].to),cnt++,v[e[i].to]=1;
    	while(cnt!=lim)
    	{
    		for(int x:ls) for(int i=head[x];i;i=e[i].nxt) if(!v[e[i].to]) iv[e[i].to]|=iv[x];
    		for(int x:ls) for(int i=head[x];i;i=e[i].nxt)
    			if(!v[e[i].to]) nw.push_back(e[i].to),v[e[i].to]=1,cnt++;
    		swap(nw,ls),nw.clear();
    	}
    	for(int i=0;i<lim;i++) rs[iv[i]]=i;
    	for(int i=0;i<lim;i++) printf("%d%c",rs[i],i==lim-1?'\n':' '),iv[i]=0;
    	if((n&(-n))!=n) return puts("-1"),void();
    	for(int i=0;i<lim;i++) for(int j=0;j<n;j++) if((i>>j)&1) iv[rs[i]]^=j;
    	for(int i=0;i<lim;i++) printf("%d%c",iv[i],i==lim-1?'\n':' ');
    }
    int main() {int Ca;for(read(Ca);Ca--;) solve();return 0;}
    
  • 相关阅读:
    一些数据集
    经典的图像匹配算法----SIFT
    LDA处理文档主题分布代码
    Dirichlet Process
    主题模型-LDA浅析
    matplotlib —— 添加文本信息(text)
    xgboost原理及应用
    XGBoost参数调优
    MySQL中实现Oracle里面 rank()over ( PARTITION BY ORDER BY) 分类分组功能
    4.12 省选模拟赛 LCA on tree 树链剖分 树状数组 分析答案变化量
  • 原文地址:https://www.cnblogs.com/pealfrog/p/15065478.html
Copyright © 2020-2023  润新知