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 }

原文地址:https://www.cnblogs.com/five20/p/8410510.html

时间: 2024-11-06 09:39:01

520的信心赛——点点玩deeeep的相关文章

8.25重庆南开CSP信心赛

8.25重庆南开CSP信心赛 A.填数字 时间限制:1s空间限制:128MB 题面描述信竞队的同学们在一个N*N的方格矩阵上填数字.开始时,所有矩阵里的数字都是0. 同学们一共给 个子矩阵填了数字,每次填的数都是从 这区间中选一个数字,然后给对应矩阵全部填上该数字.比如:第1步,选了一个子矩阵,将数字2填上:2 2 2 02 2 2 02 2 2 00 0 0 0第2步,选了一个子矩阵,将数字7填上:2 2 2 02 7 7 72 7 7 70 0 0 0第3步,选了一个子矩阵,将数字3填上:2

2015 HDU 计算机学院 院赛 1003 玩骰子

Problem Description Nias与Ains都特别喜欢玩骰子,而且都自以为比对方玩得更溜.  终于有一天,他们决定用骰子来一决高下!  一般的骰子玩法已经不足以体现他们的水平了,于是他们自创了一套玩法来PK:首先,每人掷3个骰子:之后,可以选择其中一个骰子重新掷(当然也可以放弃这一步),最后,比较投掷结果的大小,结果大的那方获胜,一样的话为平局.  大小比较规则为:  三个一样数字的骰子称为三条:两个一样数字的骰子称为对子:只有一个数字的骰子成为散牌.三条>对子>散牌.当双方结果

0825-CSP信心赛

众所周知:CSP是cost spend pay的缩写(逃) A 现代艺术 枚举每一块的上下左右极限覆盖面积 + 二阶差分 被一个数字覆盖的区域求前缀和后==1,被多个数字覆盖的区域求前缀和>=1 然后考场上没有想到枚举每一块的上下左右极限覆盖面积(其实也没想到二阶差分) 当时是枚举了几种类型,但是想不到如何统计覆盖情况,然后草草打了个不正确的解法拿了30分溜了 B [JLOI2012]树 倍增+枚举能否跳L fa[x][i]=fa[fa[x][i-1]][i-1]; dis[x][i]=dis[

繁华模拟赛 Evensgn玩序列

#include<iostream> #include<cstdio> #include<string> #include<cstring> #include<algorithm> using namespace std; const int maxn = 5000; int n,a[maxn],b[maxn],c[maxn],rka[maxn],rkb[maxn],rkc[maxn]; bool visa[maxn],visb[maxn],vi

CTYZ信心赛T5 题解

吐槽ing: 一道有趣的二进制题 注意加粗部分是限制条件 我们先考虑暴力分\(40\)分: 首先那个\(Fight\)值一看就知道是二进制. 对于这个暴力分,应该是一种很暴力(废话)的解法,我们直接从\(b\)向\(a\)枚举,然后判断这一个数合不合法,如果合法,就+1,直到找到第\(k\)大,输出答案即可. 考虑\(100pts:\) 这里我们就要开始讨论二进制算法了. 首先我们考虑巨佬站队方式的限制,对于每个询问\([a,b]\),假设巨佬的\(Fight\)值是\(p\),若\(p>b\)

CQNK信心赛(2019.8.20)

我还是太naiive A题知道要超时还是没打表 结果julaohyh 教我打了一波表之后 这不是**题吗      %一发 B题暴力写挂了 拿了20pts  还好  全排列暴力      结果正解贪心  这谁想得到 啊 思维还是太弱 C题  区间Hash+二分  我还以为是KMP  结果暴力都能拿90pts         老板还说我不会暴力  我还看错题 放波julaohyh 的题解 https://www.luogu.org/blog/HuangYuhan-Yuzhe/cqnk-xin-xi

计蒜课 八月模拟赛题解

看见机房有大佬上周写了上面的普及信心赛 于是我康了康 8月的提高组模拟赛 9月的还没开始qwq 真的 有点难 主要是我先打开了T2 我再次 对自己的数学产生了怀疑 我现在还是不会写T2 T1 又又又又都错题了 下次重建图 尽量写vector 都写 邻接表 变量差不多的容易搞混 我这个同学变又写错了 T1 :https://nanti.jisuanke.com/t/41086 题目大意就是 一个有向图 删一个点 把与他直接和间接 相连的点 删掉 然后 求删掉所有点的最小最大代价 : 为了避免这个环

[随笔]NOIP2017提高组复赛 游记

前言 真正意义上的第一篇游记,经历了第一次正式大考,希望自己能在这条道路上走得足够远... 当然最主要的梦想还是THU喔! Day -2 今天就是NOIP考前在机房呆的最后一天,上午打完了最后一场模拟赛,是NOIP模拟赛50,难以置信集训期间考了这么多场QAQ 应该这场就是信心赛了,因为好像上午要和我们联考的学校放了OD鸽子了2333(喜闻乐见) 然后蒟蒻的我信心赛只打了210分rank12 T-T,只能说RP++ 下午没有考试,于是机房内的气氛从原来的高级算法乱飞,变成了都在码最基础的模板 临

Android Study 之 初识ButterKnife(8.5.1)及简单运用

LZ-Says:突然间不知道说什么好,祝大家编码无bug吧~ 前言 话说,Android开发的兄弟们都知道,每次初始化控件,设置相应的事件,写的那点过程多而且恶心.我们先一块回顾下不堪的曾经~ 那些年... 那些年,我们是这样初始化控件: // 每次的习惯上来写一个initView()方法 tvContent = (TextView) findViewById(R.id.btn_content); // 遇到项目大的时候,这里面的东西,也曾占据半壁江山...苦不堪言 // 当然也曾封装过方法,避