• AtCoder 日立2020 ThREE


    https://atcoder.jp/contests/hitachi2020/tasks/hitachi2020_c

    题目

    某人很无聊,想给树上N个节点的每一个节点填一个1~N中的一个数。满足

    • 所有填的数字都不同
    • 距离为3的两个节点的两个数要么和是3的倍数,要么积是3的倍数

    $2leqslant Nleqslant 2 imes 10^5$

    题解

    其实我不会,这是个构造题……

    记一下之前的思路:

    树上的点可以用距离为3的倍数这个等价关系分成3个商集
    然后对3个树涂色,然后一顿乱涂,发现规约到NPC问题上去了……
    

    把数字按照mod 3分成3类:A,B,C

    相邻两个节点的颜色可以是A-B,A-C,B-C,C-C

    C可以用来代替A或B,那么用A涂白色,B涂黑色,多余的部分用C涂

    有个例外:$A+C$还不够涂白色,这时$B$肯定大于黑色的数量,因为A,B,C相差不超过1,因此等价于C大于等于黑色,用C涂黑色,剩下的随便涂

    总结一下:

    如果C大于等于黑色,那么用C涂黑色,剩下的随便涂

    如果C大于等于白色,那么用C涂白色,剩下的随便涂

    否则这时候A小于等于白色,B小于等于黑色,A涂白色,B涂黑色,不够的用C涂

    这样就解决了1棵树的相邻节点的问题,距离为3可以拆成3个树,然后就解不出来了……

    其实仍然可以用相邻节点,距离为3肯定保证不会出现A-A或B-B,这样就保证一定能构造出来

    [egin{pmatrix}0 & 1 \ 1 & 0 end{pmatrix}^3=egin{pmatrix}0 & 1\1&0end{pmatrix} ]

    AC代码

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<map>
    #define REP(i,a,b) for(register int i=(a); i<(b); i++)
    #define REPE(i,a,b) for(register int i=(a); i<=(b); i++)
    #define PERE(i,a,b) for(register int i=(a); i>=(b); i--)
    using namespace std;
    typedef long long ll;
    #define MAXN 200007
    int hd[MAXN<<1], nxt[MAXN<<1], to[MAXN<<1], m=0;
    inline void adde(int a, int b) {
    	nxt[m]=hd[a]; hd[a]=m; to[m]=b; m++;
    }
    int q[MAXN], c[MAXN], ans[MAXN], vis[MAXN];
    int use[3]={1,2,3};
    int n;
    int go(int v) {
    	if(use[v]>n) {
    		int r=use[2];
    		use[2]+=3;
    		return r;
    	}
    	int r=use[v];
    	use[v]+=3;
    	return r;
    }
    inline void bfs1() {
    	int f=0, r=0;
    	memset(vis,0,sizeof vis);
    	ans[0]=0, ans[1]=0;
    	q[f++]=1; c[1]=0; vis[1]=1; ans[0]++;
    	while(r<f) {
    		int n=q[r], s=c[n]^1; r++;
    		for(int i=hd[n]; ~i; i=nxt[i]) {
    			int t=to[i];
    			if(!vis[t]) {
    				vis[t]=1;
    				c[t]=s;
    				ans[s]++;
    				q[f++]=t;
    			}
    		}
    	}
    }
    int main() {
    	memset(hd,-1,sizeof hd);
    	scanf("%d", &n);
    	REP(i,0,n) {
    		int a,b; scanf("%d%d", &a, &b);
    		adde(a,b); adde(b,a);
    	}
    	bfs1();
    	if(ans[0]<=n/3) {
    		int now=1, c2=3;
    		REPE(i,1,n) {
    			if(c[i]==0) {ans[i]=c2;c2+=3;}
    		}
    		REPE(i,1,n) {
    			if(c[i]==1) {
    				if(now%3==0 && now<c2) now++;
    				ans[i]=now;
    				now++;
    			}
    		}
    	} else if(ans[1]<=n/3) {
    		int now=1, c2=3;
    		REPE(i,1,n) {
    			if(c[i]==1) {ans[i]=c2;c2+=3;}
    		}
    		REPE(i,1,n) {
    			if(c[i]==0) {
    				if(now%3==0 && now<c2) now++;
    				ans[i]=now;
    				now++;
    			}
    		}
    	} else {
    		REPE(i,1,n) {
    			ans[i]=go(c[i]);
    		}
    	}
    	REPE(i,1,n) { if(i>1)putchar(' ');
    		printf("%d", ans[i]);
    	}
    }
    
  • 相关阅读:
    现代程序设计 作业1
    现代程序设计课程简介
    ubuntu 下解决安装包依赖问题
    centos下安装nginx和php-fpm
    如何在本机上将localhost改为www.dev.com
    神器
    脚本监测 前十名磁盘空间用户的列表
    使用xml来显示获取的mysql数据
    linux使用脚本自动连接数据库
    shell script的连接符是逗号,不是英文的句号
  • 原文地址:https://www.cnblogs.com/sahdsg/p/12450101.html
Copyright © 2020-2023  润新知