Project Euler – Problem 12

来源:互联网 发布:js div删除classname 编辑:程序博客网 时间:2024/04/30 04:29

The sequence of triangle numbers is generated by adding the natural numbers. So the 7th triangle number would be 1 + 2 + 3 + 4 + 5 + 6 + 7 = 28. The first ten terms would be: 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, …

Let us list the factors of the first seven triangle numbers:

1: 1
3: 1,3
6: 1,2,3,6
10: 1,2,5,10
15: 1,3,5,15
21: 1,3,7,21
28: 1,2,4,7,14,28
We can see that 28 is the first triangle number to have over five divisors.

What is the value of the first triangle number to have over five hundred divisors?

28可以表示为1*28,2*14,4*7
36可以表示为1*36,2*18,3*12,4*9,6*6

观察到:
1、T / 小于T的平方根的因子 = 大于T平方根的因子
2、T / T的平方根 = T的平方根

对于每个数,其平方根两侧有相同的因子个数。

static void TriangleNumberOver500Divisors(){    int t = 1;    int a = 1;    int cnt = 0;    while (cnt < 500)    {        cnt = 0;        a += 1;        t += a;        double r = Math.Sqrt(t);        for (int i = 1; i < r; i++)        {            if (t % i == 0)                cnt += 2;        }        // 当r正好为t的因子时,r被计数了两次。        if (t == r * r)            cnt--;    }    Console.WriteLine(t);}

上面的办法速度太慢,当要求的因子个数增多时,耗时增加明显。

根据每个数可以分解为有限个素数的乘积,则
21 = (3^1)*(7^1)
28 = (2^2)*(7^1)
36 = (2^2)*(3^2)

我们用ai表示第i个素数因子,EXi表示第i个素因子的指数,D(T)表示triangle数T的因子个数。
那么T的因子可以表示为:从第i个素因子中拿出0到EXi个,从第j个素因子中拿出0到EXj个......

即,28的因子分别为 (2^0)*(7^0)=1, (2^1)*(7^0)=2, (2^2)*(7^0)=4, (2^0)*(7^1)=7, (2^1)*(7^1)=14, (2^2)*(7^1)=28。
所以,D(n)=(EXi+1)*(EXj+1)*......

D(21) = (1+1) * (1+1) = 4
D(28) = (2+1) * (1+1) = 6
D(36) = (2+1) * (2+1) = 9

另外,根据Triangle数的定义,T可以表示为N*(N+1)/2。当然,N和(N+1)必定互素,一偶一奇,不包含共同因子。那么
当N为偶数时:N/2和N+1
当N为奇数时:(N+1)/2和N
也互素!(8和9互素,4和9也互素。9和10互素,5和9也互素。相邻的两数互素,偶数折半与另一个也是互素的。)

简化D(T)计算:
D(T) = D(n)*D( (n+1) /2 ),当n为奇数。
D(T) = D(n/2)*D(n+1), 当n为偶数。

static void Find(){    int n = 3;    int Dn = 2;    int cnt = 0;    int n1, Dn1, i, ex;    int[] primeTable = GeneratePrimeTable(1000);    // 计算D(N),然后计算D(N+1),不满足则使D(N+1)成为D(N),继续往下推进。    while (cnt <= 500)    {        n += 1;        n1 = n;        if (n1 % 2 == 0)            n1 = n1 / 2;        Dn1 = 1;        for (i = 0; i < 1000; i++)        {            if (primeTable[i] * primeTable[i] > n1)            {                Dn1 *= 2;                break;            }            ex = 1;            while (n1 % primeTable[i] == 0)            {                ex++;                n1 /= primeTable[i];            }            if (ex > 1)                Dn1 *= ex;            if (n1 == 1)                break;        }        cnt = Dn1 * Dn;        Dn = Dn1;    }    Console.WriteLine((n - 1) * n / 2);}

函数中,产生素数表的函数参照Problem7的办法。

static int[] GeneratePrimeTable(int n){    int[] primeTable = new int[n];    primeTable[0] = 2;    primeTable[1] = 3;    primeTable[2] = 5;    primeTable[3] = 7;    int cnt = 3;    int p = 11;    while (cnt < n-1)    {        if (IsPrime(p))        {            cnt++;            primeTable[cnt] = p;        }        p += 2;    }    return primeTable;}static bool IsPrime(int n){    int r = (int)Math.Sqrt(n);    int f = 5;    while (f <= r)    {        if (n % f == 0)            return false;        if (n % (f+2) == 0)            return false;        f += 6;    }    return true;}


Tags: algorithm

原创粉丝点击