目录

  • 题面
  • 题面分析
    • 初读题面
    • 深入分析
    • 得出答案
      • 树形DP做法
      • 树形DP模板(仅供参考)
      • 搜索做法
      • 搜素BFS模板(仅供参考)
    • 代码

题面

一本通

LOJ

题面分析

初读题面

如果一个数 xxx 的约数和 yyy (不包括他本身)比他本身小,那么 xxx 可以变成 yyy,yyy 也可以变成 xxx。例如 444 可以变为 333,111 可以变为 777。限定所有数字变换在不超过 nnn 的正整数范围内进行,求不断进行数字变换且不出现重复数字的最多变换步数。

事实上,刚读题目时我根本没看懂。
但当我们看到首页时,就明白到底怎么做了——
这不就是个树形DP嘛!
重点就在构造这棵树上。

深入分析

首先,预处理出小于NNN的每个数的约数和a[i]a[i]a[i],其中a[i]a[i]a[i]表示iii的约数和。
再根据题目,可以得出:

对于每个数iii,如果a[i]<ia[i]<ia[i]<i,那么iii和a[i]a[i]a[i]可以互相转化,即两点间连一条边,iii为a[i]a[i]a[i]的一个儿子。

于是,隐藏在题目中的树就构造好了。

得出答案

接下来就简单了,在树上找树的直径就可以了。
这里有必要引入树的直径的概念:

树的直径,是指树上最长的简单路径。

(好吧,这是我乱写的)
求树的直径有两种方法:

树形DP做法

我们设d[i]d[i]d[i]表示以iii为根节点的所有子树中,与iii距离最远的一个节点的路径。
那么状态转移方程为:
d[i]=max(d[j]+val(i,j)),j∈son(i)d[i]=max(d[j]+val(i,j)),j∈son(i)d[i]=max(d[j]+val(i,j)),j∈son(i)
表示以子树为根节点的最大路径与当前根节点连边后的最大值即为当前的最大值。
树的直径其实就是左子树中标有颜色的边+v(1,3)++v(1,3)++v(1,3)+右子树标有颜色的点,也就是d[1]+v(1,3)+d[3]d[1]+v(1,3)+d[3]d[1]+v(1,3)+d[3].
因此在枚举i和儿子j时,直径D=max(d[i]+val+d[j])D=max(d[i]+val+d[j])D=max(d[i]+val+d[j])

树形DP模板(仅供参考)
#include <bits/stdc++.h>
using namespace std;
int n,m,ans=0,f[50039];
struct edge{int v,w;
};
vector<edge> a[50039];
inline void dp(int x,int fa){for(int i=0;i<a[x].size();i++){int son=a[x][i].v;if(son==fa) continue;dp(son,x);ans=max(ans,f[x]+f[son]+a[x][i].w);f[x]=max(f[x],f[son]+a[x][i].w);}return;
}
int main(){scanf("%d%d",&n,&m);for(int i=1;i<=m;++i){int x,y,v;scanf("%d%d%d",&x,&y,&v);a[x].push_back(edge{y,v});a[y].push_back(edge{x,v});}dp(1,0);printf("%d",ans);return 0;
}
搜索做法

搜索的做法要好理解一点,大致方法如下:
先从任意一点开始搜索,找到离这个节点最远的点mmm
再从点mmm开始搜索,找到离点mmm最远的点nnn
那么两点之间的距离即为树的直径。

搜素BFS模板(仅供参考)
#include <bits/stdc++.h>
using namespace std;
int ans,point,n,m;
int v[50039],d[50039];
vector<pair<int,int>> a[50039];
void bfs(int x){queue<int>q;memset(v,0,sizeof(v));memset(d,0,sizeof(d));q.push(x);d[x]=0;v[x]=1;ans=0;while(!q.empty()){int h=q.front();q.pop();for(int i=0;i<a[h].size();i++){int u=a[h][i].first,val=a[h][i].second;if(!v[u]){v[u]=1;d[u]=d[h]+val;q.push(u);}}}for(int i=1;i<=n;i++)if(d[i]>ans&&d[i]!=d[0])ans=d[i],point=i;return;
}
int main(){int x,y,V;scanf("%d%d",&n,&m);for(int i=1;i<=m;i++){scanf("%d%d%d",&x,&y,&V);a[x].push_back(make_pair(y,V));a[y].push_back(make_pair(x,V));}bfs(1);bfs(point);printf("%d",ans);return 0;
}

代码

(这是此题最终AC代码,上面两个只是模板)

#include <bits/stdc++.h>
using namespace std;
int n,a[50039],d[50039];
vector<int> edge[50039];
inline int dp(int x,int fa){//树形dp求树的直径int ans=0,l1=0,l2=0;register int i; for(i=0;i<edge[x].size();i++){int v=edge[x][i];if(v==fa) continue;ans=max(ans,dp(v,x));d[x]=max(d[x],d[v]);if(d[v]>l1){l2=l1;l1=d[v]+1;}else if(d[v]>l2)l2=d[v];}d[x]++;return max(ans,l1+l2);
}
int main(){scanf("%d",&n);register int i,j;for(i=1;i<=n;i++){if(a[i]<i){edge[i].push_back(a[i]);edge[a[i]].push_back(i);}for(j=i*2;j<=n;j+=i)//预处理每个数的约数和a[j]+=i;}   printf("%d",dp(1,0)-1);return 0;
}

LOJ10155 一本通1577 数字转换 题解相关推荐

  1. LOJ 10155. 「一本通 5.2 例 3」数字转换

    题目:数字转换 思路: 对于每一个数,把它和它能够转移到的数之间连一条边. 由于不存在多元环,这个图本质上是一棵树. 然后在树上求最长链的长度就可以了. 具体实现就是dfs遍历整棵树,对于以每个点ii ...

  2. 数字转换 LibreOJ - 10155

    数字转换 LibreOJ - 10155 题目 题解 AC代码 链接: 原题地址. 题目 如果一个数 x 的约数(不包括他本身)的和 y 比他本身小,那么 x 可以变成 y,y 也可以变成 x.例如 ...

  3. php数字转英文,PHP金额数字转换成英文

    PHP金额数字转换成英文 $numTable[40]="FORTY "; $numTable[50]="FIFTY "; $numTable[60]=" ...

  4. C++字符串和数字转换完全攻略

    以字符串形式存储的数字和以数字形式存储的数字之间是有区别的. 例如,字符串 "2679" 就不是一个数字:它是由 2.6.7.9 这 4 个字符的 ASCII 码组成的序列.由于字 ...

  5. 牛客题霸 [数组中只出现一次的数字] C++题解/答案

    牛客题霸 [数组中只出现一次的数字] C++题解/答案 题目描述 一个整型数组里除了两个数字之外,其他的数字都出现了两次.请写程序找出这两个只出现一次的数字. 题解: 用map来记录每个数字出现几次, ...

  6. 牛客题霸 [ 旋转数组的最小数字] C++题解/答案

    牛客题霸 [ 旋转数组的最小数字] C++题解/答案 题目描述 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转. 输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素. NOT ...

  7. 牛客题霸 [ 缺失数字] C++题解/答案

    牛客题霸 [ 缺失数字] C++题解/答案 题目描述 从0,1,2,-,n这n+1个数中选择n个数,找出这n个数中缺失的那个数,要求O(n)尽可能小. 题解: 我们可以用map来标记已出现过的数字 因 ...

  8. 牛客题霸 [数组中出现次数超过一半的数字] C++题解/答案

    牛客题霸 [数组中出现次数超过一半的数字] C++题解/答案 题解: 题意很明确 跑一遍for循环,统计每个数出现的大小 然后再跑一边循环,查看是否存在大于一半的情况 注意题目要求是大于,没有等于 代 ...

  9. python数字转换_Python实现中文数字转换为阿拉伯数字的方法示例

    本文实例讲述了Python实现中文数字转换为阿拉伯数字的方法.分享给大家供大家参考,具体如下: 一.需求 今天写了三千二百行代码. 今天写了3200行代码. 两行意思相同,只是表达方式不太能够,统一掉 ...

最新文章

  1. chrdev字符设备几种注册方式的差异
  2. 构建 RESTful Web 服务
  3. 2、AD工程创建步骤
  4. Subversion 1.5 安装配置指南
  5. Django之orm查询
  6. Magicodes.IE之导入导出筛选器
  7. PNG,GIF,JPG的区别及如何选
  8. C++里数组名+1和数组名的地址+1的区别
  9. .net框架读书笔记---虚方法
  10. Java 11新特性
  11. 特征工程系列学习(一)简单数字的奇淫技巧(下)
  12. 计算机系统基础知识——详解二进制正负数及补码设计
  13. python中的进程(二)
  14. 实用高效的5个进度管理工具推荐,项目经理快马住!
  15. SAM4E单片机之旅——22、GMAC和PHY的介绍与初始化
  16. 解散群通知怎么写_德云社演员私联初二女生,随后德云社全员退出粉丝群,什么情况?...
  17. ORB-SLAM2代码详解
  18. 怎么解决图片用PSCC打开后,白色部分全部呈现米黄色?
  19. 有道翻译爬虫 js逆向
  20. win10安装序列号

热门文章

  1. 华硕e202s安装linux系统,华硕笔记本E202S原装win10系统可以改win7吗?
  2. 苹果手机很卡怎么解决_iPhone很卡怎么办,教您如何解决iPhone很卡问题!
  3. 【SPUSKU】简述
  4. 【C++ Caffe】ubuntu下MNIST训练结果
  5. 我的世界服务器刷怪笼怎么修改,我的世界毒蜘蛛刷怪笼改造经验农场教学
  6. MySQL 字符串数字转换
  7. Ubuntu 18.04 LTS系统主题美化
  8. SAP中MRP控制者的应用理解
  9. 利用R包ggmsa进行多序列比对_2020-05-31
  10. 计算机网络基础之域名系统