520的信心赛——点点玩deeeep

Posted five20

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了520的信心赛——点点玩deeeep相关的知识,希望对你有一定的参考价值。

                                             3、点点玩 deeeep(deeeep.cpp)

描述
  点点最近迷上了 deeeep(此 de 非彼 de),在研究一个特殊的
最长树链问题(树链即树上的一条路径)。现在一棵树中的每个点
都有一个 deeeep 值(正整数)
,点点想在树中找出最长的树链,使
得这条树链上所有对应点的 deeeep 值的最大公约数大于 1。请求出
这条树链的长度。(巨说这道题很 water!
)
格式
输入格式
第 1 行:整数 n(1 ≤ n ≤ 100000),表示点的个数。
第 2~n 行:每行两个整数 x,y 表示 x 和 y 之间有边,数据保证给
出的是一棵树。
第 n+1 行:n 个整数,依次表示点 1~n 对应的权值(1 ≤ 权值 ≤
1,000,000,000)

输出格式输出一个整数,表示这条树链的长度。
样例 1
样例输入 1
4
1 2
1 3
2 4
6 4 5 2
样例输出 1
3
限制
对于 100%的数据 1≤n≤100000,1≤ai≤10^9

 

Solution:

  本题考察搜索+数学。
    实际上就是乱写暴力。bfs爆搜能ac,还比正解快,简直鬼畜。
    枚举每个约数,保留对应的边,做一次最长路径。因为一个数的约数个数可以保证,所以复杂度符合要求。
    看起来10^9很虚,但是我们分解质因数只需要预处理出3*10^4里的质数,实际上只有3000多个,3000*n完全不虚,所以我们可以先将n个数全都分解质因数。
  然后我们枚举每个质数,枚举所有包含这些质数的点,看一下这些点在树上能形成的最长的链有多长。具体做法是我们将这些点按照深度从大到小排序,然后更新每个点父亲的子树中到父亲的最长链、次长链分别是多长,乱搞一下就行了。

代码:

bfs玄学比正解快:

 1 /*莫名打的玄学复杂度bfs,结果ac——by 520*/
 2 #include<bits/stdc++.h>
 3 #define il inline
 4 using namespace std;
 5 const int maxn = 100050;
 6 int maxlen=0,rd[maxn],a[maxn];
 7 vector<int>v[maxn];
 8 il int gi()
 9 {
10     int a=0;char x=getchar();bool f=0;
11     while((x<0||x>9)&&x!=-)x=getchar();
12     if(x==-)x=getchar(),f=1;
13     while(x>=0&&x<=9)a=a*10+x-48,x=getchar();
14     return f?-a:a;
15 }
16 struct node{
17     int x;
18     int len;
19     int gcd;
20 };
21 il void bfs(int x,int len,int gcd)
22 {
23     node n1,n2;
24     queue<node>q;
25     n1.x=x; n1.len=len; n1.gcd=gcd;
26     q.push(n1);
27     while(!q.empty())
28     {
29         node n1=q.front(); q.pop();
30         int nx=n1.x, nlen=n1.len, ngcd=n1.gcd;
31         maxlen=max(nlen, maxlen);
32         for(int i=0;i<v[nx].size();i++)
33         {
34             int next=v[nx][i], usegcd=__gcd(a[next],ngcd);
35             if(usegcd==1){
36                 n2.gcd=a[next]; n2.len=1; n2.x=next;
37                 q.push(n2);
38             }
39             else{
40                 n2.gcd=usegcd; n2.len=1+nlen; n2.x=next;
41                 q.push(n2);
42             }
43         }
44     }
45 }
46 int main()
47 {
48     freopen("deeeep.in","r",stdin);
49     freopen("deeeep.out","w",stdout);
50     int x,y,n=gi(),go=0;
51     for(int i=2;i<=n;i++)
52     {
53         x=gi(),y=gi();
54         v[x].push_back(y);
55         rd[y]++;
56     }
57     for(int i=1;i<=n;i++)
58     {
59         if(rd[i]==0)go=i;
60         a[i]=gi();
61     }
62     bfs(go,1,a[go]);
63     printf("%d",maxlen);
64     return 0;
65 }

 

 

正解:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 #include <cmath>
 6 #include <vector>
 7 #include <map>
 8 using namespace std;
 9 int n,m,cnt,ans,tot,mor;
10 const int maxn=100010;
11 int to[maxn<<1],nxt[maxn<<1],head[maxn],v[maxn],d1[maxn],d2[maxn],p[103600],fa[maxn],dep[maxn],pri[3600];
12 bool np[33000];
13 vector<int> s[103600];
14 map<int,int> mp;
15 int rd()
16 {
17     int ret=0;  char gc=getchar();
18     while(gc<0||gc>9) gc=getchar();
19     while(gc>=0&&gc<=9)   ret=ret*10+gc-0,gc=getchar();
20     return ret;
21 }
22 void dfs(int x)      
23 {
24     for(int i=head[x];i!=-1;i=nxt[i])   if(to[i]!=fa[x])    fa[to[i]]=x,dep[to[i]]=dep[x]+1,dfs(to[i]);
25 }
26 bool cmp1(int a,int b)
27 {
28     return s[a].size()>s[b].size();
29 }
30 bool cmp2(int a,int b)  
31 {
32     return dep[a]>dep[b];
33 }
34 void updata(int a,int b) 
35 {
36     if(d1[b]>d1[a])  d2[a]=d1[a],d1[a]=d1[b];
37     else    d2[a]=max(d2[a],d1[b]);
38 }
39 void add(int a,int b)  
40 {
41     to[cnt]=b,nxt[cnt]=head[a],head[a]=cnt++;
42 }
43 int main()
44 {
45     freopen("deeeep.in","r",stdin);
46     freopen("deeeep.out","w",stdout);
47     n=rd();
48     int i,j,a,b;
49     memset(head,-1,sizeof(head));
50     for(i=1;i<n;i++) a=rd(),b=rd(),add(a,b),add(b,a);
51     for(i=1;i<=n;i++)    v[i]=rd(),m=max(m,v[i]);      
52     m=ceil(sqrt(1.0*m));         
53     for(i=2;i<=m;i++)            
54     {
55         if(!np[i])  pri[++tot]=i,mp[i]=tot; 
56         for(j=1;j<=tot&&i*pri[j]<=m;j++)
57         {
58             np[i*pri[j]]=1;
59             if(i%pri[j]==0) break;
60         }
61     }
62     dep[1]=1,dfs(1),mor=tot;  
63     for(i=1;i<=n;i++)
64     {
65         for(j=1;j<=tot&&pri[j]*pri[j]<=v[i];j++)
66         {
67             if(v[i]%pri[j]==0)
68             {
69                 s[j].push_back(i);  
70                 while(v[i]%pri[j]==0)   v[i]/=pri[j];
71             }
72         }
73         if(v[i]>1)
74         {
75             if(mp.find(v[i])==mp.end()) mp[v[i]]=++mor;
76             s[mp[v[i]]].push_back(i);
77         }
78     }
79     ans=1;
80     for(i=1;i<=mor;i++)  p[i]=i;
81     sort(p+1,p+mor+1,cmp1);
82     for(i=1;i<=mor;i++)
83     {
84         b=p[i];
85         if(s[b].size()<=ans) break;
86         sort(s[b].begin(),s[b].end(),cmp2);
87         for(j=0;j<s[b].size();j++)   a=s[b][j],d1[a]++,d2[a]++,ans=max(ans,d1[a]+d2[a]-1),updata(fa[a],a);
88         for(j=0;j<s[b].size();j++)   a=s[b][j],d1[a]=d2[a]=d1[fa[a]]=d2[fa[a]]=0;
89     }
90     printf("%d",ans);
91     return 0;
92 }

 

以上是关于520的信心赛——点点玩deeeep的主要内容,如果未能解决你的问题,请参考以下文章

2021.11.18-NOIP模拟测试信心赛

8.25重庆南开CSP信心赛

0820-信心赛

国庆“信心赛”

0825-CSP信心赛

CTYZ信心赛T5 题解