SGU 108.Self-numbers II
时间限制: 0.5 sec.
空间制限: 4096 KB
题目描述
1949年印度数学家D.R. Kaprekar发现了一个称为“自我数”的数。对于任意正整数 n, 定义 d(n) 为n 再加上它的各位数字之和。例如, d(75) = 75 + 7 + 5 = 87。给定任意n作为开始点,你可以构造出一个无穷增长序列, d(n), d(d(n)), d(d(d(n))), .... 例如,你以33开始,下一个数是 33 + 3 + 3 = 39, 再下一个是 39 + 3 + 9 = 51, 再下一个是 51 + 5 + 1 = 57, 继续如此就可以产生如如下递增序列:33, 39, 51, 57, 69, 84, 96, 111, 114, 120, 123, 129, 141, ... 数字n被称为d(n)的产生器 。在上述的序列中, 33为39的产生器, 39为51的产生器, 51为57的产生器,等等。有些数有超过一个的产生器: 例如, 101有两个产生器,91 和100。 一个数如果没有产生器就是一个 自我数。 让a[i]表示第i个自我数。有13个数a[1]..a[13]小于100: 1, 3, 5, 7, 9, 20, 31, 42, 53, 64, 75, 86, 和97. (第一个自我数[1]=1,第二个自我数a[2] = 3,:, 第十三个自我数a[13]=97);
输入
输入包含整数 N, K, s1...sk. (1<=N<=10^7, 1<=K<=5000) 用空格或者空行分开。
输出
第一行打印一个数 -在区间 [1..N]内所包含的“自我数”的总数。第二行包含K个数 - a[s1]..a[sk], 用空格分开。输入保证所有的自我数a[s1]..a[sk] 在区间[1..N]内。 (例如当N = 100, sk 可以为1..13 而不能为14,因为第14个自我数a[14] = 108, 108 > 100)
样例输入
100 10
1 2 3 4 5 6 7 11 12 13
样例输出
13
1 3 5 7 9 20 31 75 86 97
{============================}
分析:
思路还是比较好给出的,用类似筛选素数的方法筛选自我数。
但是要注意到题目限制的空间仅有4M,不够开10^7 那么大的数组,于是进一步分析问题我们发现每一次拓展出来的数最多比原数大63!
这是由于最多不过7位数,假设每一位都是9的话,拓展出来的数才大 7*9=63.
所以我们,对拓展出来的数取模,再用数组存下来。
至于输出自我数,经过测试,在SGU的数据里自我数的答案没有超过10^6 刚好用掉4M的空间 ⊙﹏⊙b汗
最保险的方法还是仅将需要的自我数号码存下来,排序后用二分查找判断当前找到的数是否是需要存下的,最后再将存下的数按照读入的顺序输出
参考代码(偷懒版本,不过更快)
#include<cstdio> int n, m, k; bool pd[100]; int f[1000000], tol; int Find (int x) { for (k = 0; x != 0; x /= 10) k += x % 10; return k; } void init() { int i, j; tol = 0, j = 0; for (i = 1; i <= n; i++) { if (!pd[i % 100]) f[++tol] = i; else pd[i % 100] = false; //这里用了个小技巧,大大减少取模的次数,很容易想明白 if (i % 10 == 0) j = i + Find (i); else j += 2; pd[j % 100] = true; } } int main() { scanf ("%d%d", &n, &m); init(); printf ("%d\n", tol); for (int i = 1; i <= m; i++) { scanf ("%d", &k); printf ("%d ", f[k]); } return 0; }
http://www.cnblogs.com/keam37/ keam所有 转载请注明出处