二刷提高课,题解目录在这里— 提高课的题解目录
其实只要接触过这种约数的思想,很容易就会想到用向后累加的方法
在N*log(N)的时间内求出所有数的约数之和或者约数个数
但是这里当求完之后我们如何建边如何遍历求出最大的转换次数的
我们可以发现其实就是求直径的问题
但是!这有可能并不是一颗树,有可能有多课,所以我们需要多次遍历
有向边其实就可以了但是这里使用无向边试一下
#include<cstring>
#include<iostream>
using namespace std;
const int N=5e5+10,M=2*N;
int h[N],ne[M],de[M];
int n,dix,res;
int d1[N],d2[N],sum[N];
bool st[N];
void add(int a,int b)
{
de[dix]=b,ne[dix]=h[a],h[a]=dix++;
}
int dfs(int u,int f)
{
for(int i=h[u];~i;i=ne[i])
{
int j=de[i];
if(j==f)continue;
int t;
if(st[j])t=d1[j];
else
{
st[j]=true;
t=dfs(j,u)+1;
}
if(t>d1[u])d2[u]=d1[u],d1[u]=t;
else if(t>d2[u])d2[u]=t;
}
res=max(res,d1[u]+d2[u]);
return d1[u];
}
int main()
{
cin>>n;
memset(h,-1,sizeof h);
for(int i=1;i<=n;i++)
{
for(int j=i+i;j<=n;j+=i)sum[j]+=i;
}
for(int i=2;i<=n;i++)
{
if(sum[i]<i)
{
add(sum[i],i);
add(i,sum[i]);
}
}
for(int i=1;i<=n;i++)
{
if(!st[i])st[i]=true,dfs(i,-1);
}
cout<<res;
}