1 条题解

  • 0
    @ 2026-4-29 16:41:23

    题目大意

    给定 nn 个点,两点之间有一条从编号小的点到编号大的点有向边,要求给这些边染上三种颜色,使得不存在一条长度超过 33 的相同颜色的路径。

    简单分析

    首先可以注意到题目中的数字 33,为什么出题人要用 33 这个数字而非 22 呢?其实这个数字用得很妙。那么接下来请看笔者娓娓道来。

    如果我们把所有边都染成一个颜色,由于 xix_i 的最大值不超过 101810^{18},那么可以发现从一个点开始,每走一步至少会乘 22,最多可以一口气走 6060 步,然后就不能走了。

    我们不妨将这 6060 步形成的链提出来,然后将前 2020 步染成颜色 11,中间 2020 步染成颜色 22,最后 2020 步染成颜色 33这样我们就有了 00 分的成绩

    那我们也许可以将第 ii 步染成 imod3+1i\bmod 3+1 ,但是实际上这条链并非与其他边没有关系,我们如果只考虑两者之间的相对关系,是可能影响正确性的。

    考虑一个数的 6060 个二进制位,将其分块,每 44 位分为一个小块,每 44 小块分为一个大块,最后会分出 44 个大块。可以将同一小块内的点两两连边染成颜色 11,同一大块内不同小块的点两两连边染成颜色 22,剩下的边染成颜色 33,这样做为什么是正确的呢?考虑从一个点开始走,如果要走三条相同颜色的边,那么第四步一定会走一条不同颜色的边。

    #include<iostream>
    #include<cstdio>
    
    using namespace std;
    typedef long long ll;
    const int N=1005;
    
    int n;
    ll a[N],val[N];
    int color(int x,int y){
    	if(x/4==y/4)return 1;
    	else if(x/16==y/16)return 2;
    	else return 3;
    }
    int main(){
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++)scanf("%lld",a+i);
    	for(int i=1;i<=n;i++)val[i]=63-__builtin_clzll(a[i]);
    	for(int i=1;i<=n;i++){
    		for(int j=1;j<i;j++){
    			if(a[i]%a[j]==0)printf("%d%c",color(val[i],val[j])," \n"[j==i-1]);
    			else printf("%d%c",rand()%3+1," \n"[j==i-1]);
    		}
    	}
    	return 0;
    }
    
    • 1

    信息

    ID
    10842
    时间
    1000ms
    内存
    512MiB
    难度
    9
    标签
    递交数
    11
    已通过
    5
    上传者