各位和整除数的问题

来源:互联网 发布:牛仔衬衫 男 知乎 编辑:程序博客网 时间:2024/06/12 01:25

设某特定的数为,该数的所有位数之和可被该数整除,比如说 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

原创粉丝点击