设某特定的数为,该数的所有位数之和可被该数整除,比如说 12 => 1 + 2 = 3|12。给定 n,找出所有小于 n 的满足该条件的整数的个数。
--------------------------------------------------------------------------------
若可以这么想:比如说,举一个响亮点儿的数:69吧。6 + 9 = 15->1 + 5 = 6,也就是直到加为一个个位数的话,那么这个数,将是原数除以9的余数。也有人将这一余数称为数的“根”。
ttklboy同学对此给了详细的思想:
每个数的各位相加的和就是该数除9的余数。
当余数是 0 或 1 时,这个数一定满足条件。比如 1,10,19,28。
当余数是 2 时,这个数可以表示为 2+9*x,当x为偶数时,该数满足条件,x为奇数时,不满足条件,所有余数为2 的数中有一半满足条件。
余数是 4 时,这个数可以表示为 4+9*x,当x是4的整数倍时,该数满足条件,所以余数为4的数中有四分之一满足条件。
余数为 5,7,8 时情况相似。
而余数为 3 时,该数可以表示为 3+9*x,该数一定满足条件,因为式中 9 就是 3 的倍数。
余数为 6 时,该数可表示为 6+9*x,该数只有一半满足条件,因为只要保证 x 为偶数就可以。
我将他的思想实现如下:
view plaincopy to clipboardprint?
#include <iostream>
using namespace std;
void main()
{
const unsigned long n = 100;
if ( n < 10 ) cout << "结果为:" << n << endl;
else
{
// a 表示分为多少长度为 9 的段,b 表示分段后剩下的数,c 对所有段的每一列进行加合
// 每段从余数为 1 起,到余数为 0 结束
// a 初始 - 1 表示不算一位数的那一段,即 x 不得为 0
unsigned long a = n / 9 - 1;
unsigned long b = n % 9;
unsigned long c = a + a + a / 2 + a + a / 4 + a / 5 + a / 2 + a / 7 + a / 8;
a++; // 恢复计算所有段,包括一位数段
// 剩余的几个数所在的段可能满足条件
c += ( b >= 1 );
c += ( b >= 2 && a % 2 == 0 ); // 因为一位数段必满足条件, 相当于从两位数段开始计算
c += ( b >= 3 ); // 并计算到剩余数所在的段
c += ( b >= 4 && a % 4 == 0 );
c += ( b >= 5 && a % 5 == 0 );
c += ( b >= 6 && a % 2 == 0 );
c += ( b >= 7 && a % 7 == 0 );
c += ( b >= 8 && a % 8 == 0 );
cout << "结果为:" << c + 9 << endl;
}
system("pause");
}
#include <iostream>
using namespace std;
void main()
{
const unsigned long n = 100;
if ( n < 10 ) cout << "结果为:" << n << endl;
else
{
// a 表示分为多少长度为 9 的段,b 表示分段后剩下的数,c 对所有段的每一列进行加合
// 每段从余数为 1 起,到余数为 0 结束
// a 初始 - 1 表示不算一位数的那一段,即 x 不得为 0
unsigned long a = n / 9 - 1;
unsigned long b = n % 9;
unsigned long c = a + a + a / 2 + a + a / 4 + a / 5 + a / 2 + a / 7 + a / 8;
a++; // 恢复计算所有段,包括一位数段
// 剩余的几个数所在的段可能满足条件
c += ( b >= 1 );
c += ( b >= 2 && a % 2 == 0 ); // 因为一位数段必满足条件, 相当于从两位数段开始计算
c += ( b >= 3 ); // 并计算到剩余数所在的段
c += ( b >= 4 && a % 4 == 0 );
c += ( b >= 5 && a % 5 == 0 );
c += ( b >= 6 && a % 2 == 0 );
c += ( b >= 7 && a % 7 == 0 );
c += ( b >= 8 && a % 8 == 0 );
cout << "结果为:" << c + 9 << endl;
}
system("pause");
}
--------------------------------------------------------------------------------
但原题不是这样的,只许合一次,不迭代。
但是这种思想还是值得扩展的。
试想,还以 69 这个响亮的数字来举例,6+9 = 15,那么 69-15 呢?54,是9的倍数!
我试了好多数,发现,对于数 n,设 f(n) 为 n 的各位加和,则 n = f(n) + 9x !
好了,如果想满足条件,则必须 f(n) | 9x,也就是说,9x 共有多少个约数,对于此特定的 x,就有多少个 n 满足条件。
设 x = a^p + b^q + c^r +.....,其中 a, b, c 为质数,p,q,r 为指数,则 x 的从 1 到 x 的全约数个数为 (p+1)(q+1)(r+1).......注意这里,全约数的个数,就是符合条件的 f(n) 的个数,也就是符合条件的 n 的个数。别忘了,这里还有一个 9 = 3^2 的事儿。若 x 含有质因数 3,需要合并进去,否则的话,9x 的全约数的个数还要乘以一个 (2 + 1)
这就好办了!对于 9x <= n / 2 以内的部分,直接可以通过求质约数的分布,由上式直接得出个数,但是对于 n/2 到 n 的部分,需要考虑 f(n) + 9x 会超过 n 的情况,注意这里 f(n) 属于集合 {m| 9x % m == 0 }。这里,由于 f(n) 最大可为 9x,故而以 n / 2 为分界。目前没有找到好办法,似乎必须把所有约数给算出来,而不单单是数个数就完了的……
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/hikaliv/archive/2009/06/04/4243089.aspx