数字转换

题目描述

如果一个数 x 的约数和 y (不包括他本身)比他本身小,那么 x 可以变成 yy 也可以变成 x。例如 4 可以变为 3111 可以变为 7。限定所有数字变换在不超过 n 的正整数范围内进行,求不断进行数字变换且不出现重复数字的最多变换步数。

输入格式

输入一个正整数 n。

输出格式

输出不断进行数字变换且不出现重复数字的最多变换步数。

样例

样例输入

7

样例输出

3

样例说明

一种方案为 4→3→1→7

数据范围与提示

对于 100% 的数据,1n50000。

 

——————————————————————————————————————————————————————————

看上去是一个数学相关的题目实际上是一个图论题。

题目要求每个点可以转换成约数和的条件是和的大小小于当前的数。所以每个点要么可以向前变,要么不在向前变。如果以约数为根那么就得到许多的树,也就是说,他们是一些森林,约数和是父亲。然后求最长的变换距离就是求最长连,树上DP就可以了。

——————————————————————————————————————————————————————————

 

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int maxn=50010;
 4 int sum[maxn],dis1[maxn],dis2[maxn];
 5 int n;
 6 void readint(int &x)
 7 {
 8     int f=1;
 9     char c=getchar();
10     for(;c<'0' || c>'9';c=getchar())if(c='-')f=-f;
11     x=0;
12     for(;c<='9' && c>='0';c=getchar())x=x*10+c-'0';
13     x*=f;
14 }
15 void writeint(int x)
16 {
17     if(x<0)
18     {
19         putchar('-');
20         x=-x;
21     }
22     if(x>9)writeint(x/10);
23     putchar(x%10+'0');
24 }
25 void init()
26 {
27     for(int i=1;i<=n;++i)
28         for(int j=2;i*j<=n;++j)
29             sum[i*j]+=i;
30 }
31 void dp()
32 {
33     for(int i=n;i>0;--i)
34     {
35         int j=sum[i];
36         if(j<i)
37         {
38             if(dis1[i]+1>dis1[j])
39             {
40                 dis2[j]=dis1[j];
41                 dis1[j]=dis1[i]+1;
42             }
43             else if(dis1[i]+1>dis2[j])
44                 dis2[j]=dis1[i]+1;
45         }
46     }
47 }
48 int main()
49 {
50     readint(n);
51     init();
52     for(int i=1;i<n;++i)cerr<<i<<":"<<sum[i]<<endl;
53     dp();
54     int ans=0;
55     for(int i=1;i<=n;++i)ans=ans>dis1[i]+dis2[i]?ans:dis1[i]+dis2[i];
56     writeint(ans);
57     return 0;
58 }
View Code

 

posted on 2018-11-04 15:17  gryzy  阅读(469)  评论(0编辑  收藏  举报

导航