数字转换
对每个数x,若其真因子和y<x,则x与y可互
正文
/*
原题:数字转换(一本通 5.2 例3)
题意:对每个数 x,若其真因子和 y<x,则 x 与 y 可互变;求在不超过 n 的正整数里最长变换步数。
思路:以 x->y(y<x) 建森林(每个点至多一条向更小的边),答案即整片森林的最长路径(直径)长度。
复杂度:O(n log n) 求因子和 + O(n) 求直径;空间 O(n)。
易错点:变换只能在正整数范围内,y 必须 ≥1;最长路径用两次 BFS。
*/
#include <bits/stdc++.h>
using namespace std;
const int N=50005;
vector<int> g[N];
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
int n;
cin>>n;
vector<int> d(n+1,0);
for(int i=1;i<=n/2;i++)
for(int j=i*2;j<=n;j+=i) d[j]+=i;
for(int i=1;i<=n;i++)
if(d[i]<i&&d[i]>=1){
g[i].push_back(d[i]);
g[d[i]].push_back(i);
}
vector<int> dist(n+1,-1);
int ans=0;
for(int i=1;i<=n;i++){
if(dist[i]<0){
queue<int> q;
q.push(i);
dist[i]=0;
int far=i;
while(!q.empty()){
int u=q.front();q.pop();
for(int v:g[u])
if(dist[v]<0){
dist[v]=dist[u]+1;
q.push(v);
if(dist[v]>dist[far])far=v;
}
}
for(int j=1;j<=n;j++)dist[j]=-1;
q.push(far);
dist[far]=0;
int far2=far;
while(!q.empty()){
int u=q.front();q.pop();
for(int v:g[u])
if(dist[v]<0){
dist[v]=dist[u]+1;
q.push(v);
if(dist[v]>dist[far2])far2=v;
}
}
ans=max(ans,dist[far2]);
}
}
cout<<ans<<"\n";
return 0;
}
一本通·提高篇的其它内容
- 活动安排
- 种树
- 喷水装置
- 加工生产调度
- 智力大冲浪
- 数列极差
- 数列分段
- 线段
- 家庭作业
- 钓鱼
- 糖果传递
- 愤怒的牛
- Best Cow Fences
- 曲线
- 数列分段 II
- 扩散
- 灯泡
- 传送带
- 数的划分
- 生日蛋糕
- 小木棍
- Addition Chains
- 埃及分数
- 平板涂色
- 质数方阵
- 靶形数独
- 电路维修
- 魔板
- Knight Moves
- 棋盘游戏
- Keyboarding
- 移动玩具
- 山峰和山谷
- Oulipo
- 图书管理
- Power Strings
- Seekthe Name, Seek the Fame
- Friends
- A Horrible Poem
- Beads
- Antisymmetry
- 门票
- 收集雪花
- 剪花布条
- Power Strings
- Radio Transmission
- OKR-Periods of Words
- 似乎在梦中见过的样子
- Censoring
- Phone List
- The XOR Largest Pair
- Nikitosh 和异或
- Immediate Decodability
- L 语言
- Secret Message 秘密信息
- 背单词
- The Xor-longest Path
- Keywords Search
- 玄武密码
- Censoring