Problem Description
通常来说,题面短的题目一般都比较难,所以我要把题面写得很长很长。
通常来说,题面短的题目一般都比较难,所以我要把题面写得很长很长。
通常来说,题面短的题目一般都比较难,所以我要把题面写得很长很长。
鸽子数字由以下过程定义:从任何正整数开始,将数字替换为其各个数位的平方和,并重复该过程,直到该数字等于1。如果不能,则这个数字不是鸽子数。
例如7是鸽子数,因为7->49->97->130->10->1。(7*7=49,4*4+9*9=97,9*9+7*7=130....如此类推)
显然1是第一个鸽子数。
有Q个询问,每个询问给出一个数k,你需要输出第k个鸽子数
Input
第一行一个Q,代表询问的个数(Q<=100000)
接下来Q行,每行一个数字k(k<150000)
Output
每行输出一个数,代表第k个鸽子数
Sample Input
2
1
2
Sample Output
1
7
解题思路:
(1)这道题得先理解一下鸽子数的含义:从任何正整数开始,将数字替换为其各个数位的平方和,并重复该过程,直到该数字等于1。如果不能,则这个数字不是鸽子数。
(2)题目是将自然数从小到大排序,输出第k个鸽子数;
这道题可以先预处理,先将150000内的鸽子数先处理出来,才不用每次查询每次再循环一遍鸽子数,肯定会超时
注意:先将150000内的鸽子数先处理出来,这里特别要注意,不能从i = 1到 i = 150000 找鸽子数,因为该范围的鸽子数肯定小于150000(并不是所有的数都是鸽子数),所以应范围稍微大于150000;
代码如下:
1 #include<iostream> 2 using namespace std; 3 4 5 int get(int tmp) //将每个正整数分解成各位数的平方和; 6 { 7 int ans = 0; 8 while (tmp>0) 9 { 10 ans += (tmp% 10) * (tmp% 10); 11 tmp = tmp/ 10; 12 } 13 14 15 return ans; 16 } 17 bool gezi(int n) 18 { 19 int temp = n; 20 while (1) 21 { 22 temp = get(temp); //获得分解后的数,比如get(49)获得97(4²+9²); 23 if (temp == 2 ||temp == 3 ||temp == 4 ||temp == 5||temp == 6 || temp == 16 || temp == 20|| temp == 37 || temp == 42 || temp == 58 ||temp == 89 || temp == 145 ) 24 { //这个优化源于我一开始题目读错,以为是输入该数,判断是否为鸽子数,题目有2,结果2的分解是一个死循环,将2分解过程中的一个循环中的数都不会符合条件;再加上3,4,5,6,均不是鸽子数,因为题目说7是第二个鸽子数; 25 return false; 26 } else 27 if (temp == 1) 28 { 29 return true; 30 } 31 } 32 } 33 34 35 long long int count1 = 1; 36 long long int flag[1500005]; 37 int q ,n; 38 int main() 39 { 40 cin>>q; 41 for( long long int i = 1 ;i <= 1050000;i++) //这里不能只是到150000 因为这样的话找不到鸽子数范围到150000,范围得开再大点; 42 { 43 if(gezi(i)) 44 { 45 flag[count1] = i; //将鸽子数记录下来,并记录其序号,方便后面直接输出; 46 count1++; 47 } 48 } 49 for( int i = 0 ; i < q;i++) 50 { 51 cin>>n; 52 cout<<flag[n]<<endl; //直接根据序号输出鸽子数; 53 } 54 return 0; 55 } 56 57 58
原文地址:https://www.cnblogs.com/yewanting/p/10543792.html
时间: 2024-10-08 15:30:28