1 条题解
-
0
题目大意
给定 个点,两点之间有一条从编号小的点到编号大的点有向边,要求给这些边染上三种颜色,使得不存在一条长度超过 的相同颜色的路径。
简单分析
首先可以注意到题目中的数字 ,为什么出题人要用 这个数字而非 呢?其实这个数字用得很妙。那么接下来请看笔者娓娓道来。
如果我们把所有边都染成一个颜色,由于 的最大值不超过 ,那么可以发现从一个点开始,每走一步至少会乘 ,最多可以一口气走 步,然后就不能走了。
我们不妨将这 步形成的链提出来,然后将前 步染成颜色 ,中间 步染成颜色 ,最后 步染成颜色 ,
这样我们就有了 分的成绩。那我们也许可以将第 步染成 ,但是实际上这条链并非与其他边没有关系,我们如果只考虑两者之间的相对关系,是可能影响正确性的。
考虑一个数的 个二进制位,将其分块,每 位分为一个小块,每 小块分为一个大块,最后会分出 个大块。可以将同一小块内的点两两连边染成颜色 ,同一大块内不同小块的点两两连边染成颜色 ,剩下的边染成颜色 ,这样做为什么是正确的呢?考虑从一个点开始走,如果要走三条相同颜色的边,那么第四步一定会走一条不同颜色的边。
#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
- 上传者