题目链接
Educational Codeforces Round 58 (Rated for Div. 2) D. GCD Counting
题意
给你一个n
个点的带权树,第i
个点的权值为a[i]
求一条树上最长的路径,满足路径上所有点权的gcd
不为1
。
1
<
=
n
<
=
2
∗
1
0
5
1<=n<=2*10^5
1<=n<=2∗105
1
<
=
a
i
<
=
2
∗
1
0
5
1<=a_i<=2*10^5
1<=ai<=2∗105
做法
首先要想到,gcd
是质因子就足够了,也就是说,肯定存在一条最长路径公约数是质数。
之后对于一个小于
2
∗
1
0
5
2*10^5
2∗105的数,他最多存在7
个质因子
这里是因为,
2
∗
3
∗
5
∗
7
∗
11
∗
13
∗
17
=
510510
>
2
∗
1
0
5
2*3*5*7*11*13*17=510510>2*10^5
2∗3∗5∗7∗11∗13∗17=510510>2∗105
所以对于树上的每个点,只需要求这些质因子最多能向下延伸的长度。
我们就dp[i][j]
为以i为起点的向i的子树延伸的gcd
为a[i]
的第j个质因子的最长链的长度。
那么每次更新dp[i][j]
一定是他某个儿子也含有这个质因子,我们想要更新dp[i][j]
就要知道这个质因子是他儿子的第几个质因子,
所以我们预处理的时候用map
存储,map[pair<i,j>]=k
表示i
在j
中是第k
个质因子。
存储质因子用vector
存储,G[i][j]
表示i的第j
个质因子是哪个。
这样我们就可以得到更新dp[i][j]
的转移方程
设当前访问的结点为rt
,要转移的质因子为第j
个,当前访问的儿子为to
if(a[to]%G[rt][j]==0)
int pos=mp[pii(G[rt][j],to)];//rt的第j个质因子是to的第pos个质因子
dp[rt][j]=max(dp[rt][j],dp[to][pos]+1);
类似dp
求树的直径,我们对所有儿子中的可更新父亲第j
个因子的dp
值取前两大
也就是以rt
为根的子树内,gcd
为a[rt]
第j
个质因子的最长路径。
最后对每个子树内每个质因子能达到的最长路径取max
就是答案。
代码
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<map>
#include<vector>
using namespace std;
typedef pair <int, int> pii;
const int maxn = 2e5+5;
int a[maxn];
int dp[maxn][10];
vector<int> G[maxn];
vector<int> zhuan[maxn];
vector<int> vec[maxn];
map<pii,int> mp;
int ans=0;
void dfs(int rt,int fa)
{
for(int i=0;i<G[rt].size();i++) dp[rt][i]=1;
int maxx1[10],maxx2[10];
for(int i=0;i<10;i++)
{
maxx1[i]=0;
maxx2[i]=0;
}
for(int i=0;i<vec[rt].size();i++)
{
int to=vec[rt][i];
if(to==fa) continue;
dfs(to,rt);
for(int j=0;j<G[rt].size();j++)
{
if(a[to]%G[rt][j]==0)
{
int pos=mp[pii(G[rt][j],to)];//rt的第j个质因子是to的第pos个质因子
int tmp=dp[to][pos];
if(maxx1[j]<tmp)
{
maxx2[j]=maxx1[j];
maxx1[j]=tmp;
}
else if(maxx2[j]<tmp)
{
maxx2[j]=tmp;
}
}
}
}
for(int i=0;i<G[rt].size();i++)
{
dp[rt][i]+=maxx1[i];
ans=max(ans,maxx1[i]+maxx2[i]+1);
}
return ;
}
int main()
{
int n,u,v;
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=n;i++)
{
int k=a[i];
for(int j=2;j*j<=k;j++)
{
if(k%j==0)
{
G[i].push_back(j);
mp[pii(j,i)]=G[i].size()-1;
while(k%j==0) k/=j;
}
}
if(k>1)
{
G[i].push_back(k);
mp[pii(k,i)]=G[i].size()-1;
}
}
for(int i=1;i<=n-1;i++)
{
scanf("%d%d",&u,&v);
vec[u].push_back(v);
vec[v].push_back(u);
}
dfs(1,-1);
printf("%d\n",ans);
return 0;
}