1. 程式人生 > >數字轉換

數字轉換

題目描述

如果一個數 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