UVa 106 - Fermat vs. Pythagoras 素勾股数

http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&category=&problem=42&mosmsg=Submission+received+with+ID+13714821


题目大意:

给你一个N,计算出1-N内所有的勾股数,要求a和b和c互质,同时计算p,p表示1-N中不能构成勾股数的数字的个数,其中没有互质的也算,比如6,8,10也算算,如果N是10,那么p就是4。

由于给的N的范围是1000000以内,所以用普通的枚举的方法肯定会TLE的,所以需要进行优化。


首先考虑平方数的性质,对于一个奇数(2n+1),(2n+1)2 = 4(n2 + n) + 1,所以 (2n+1)2 = 1 (mod 4).

对于一个偶数(2n),(2n)2 = 4n2,所以(2n)2 = 0 (mod 4)。

所以如果一个数要是平方数,那么这个数肯定mod 4余一或者余零。

 

首先,x,y互质,所以x和y中至少有一个奇数。考虑上面说过的平方数的性质,x和y中只有一个是奇数。证明如下:

  先假设x和y都为奇数,那么x = 2m + 1, y = 2n + 1,所以 x2 + y2 = (2m+1)2 + (2n+1)2 = 4(m2 + n2 + m + n) + 2 = 2 (mod 4),所以明显不是平方数。所以x和y中只能有一个奇数。

又z和x,y都互质,且x,y中有一个偶数,那么z必定也是奇数。


欧几里得法则:x = sqrt(mn), y = (m - n)/2, z = (m + n)/2.(其中m、n同奇或者同偶,并且mn是完全平方数)

证明:x2 = mn , y2 = (m2 + 2mn + n2)/4, z2 = (m2 + 2mn + n2)/4, 易得x2 + y2 = z2,,且按照对m和n的限制,x,y和z均为整数。


丢番图法则: x = m + sqrt(2mn), y = n + sqrt(2mn), z = m + n + sqrt(2mn).(其中2mn为完全平方数)

证明:x2 = m2 + 2mn + 2m * sqrt(2mn), y2 = n2 + 2mn + 2n * sqrt(2mn), z2 = m2 + n2 + 4mn + 2(m + n) * sqrt(2mn). 易知 x2 + y2 = z2,且按照对m和n的限制,x,y和z均为整数。

毕达哥拉斯法则: x = 2n + 1,  y = 2n2 + 2n,  z = 2n+ 2n + 1.(n >= 1)即在一组勾股数中,当最小边为奇数的时候,它的平方正好等于另外两个连续的正整数之和。

证明:x2 = (2n + 1)2 = 4n2 + 4n + 1 = (2n2 + 2n) + (2n2 + 2n + 1),易知 (2n + 1)2 + (2n2 + 2n)2 = (2n2 + 2n + 1)2


柏拉图法则:x = 2n, y = n2 - 1, z = n2 + 1.(n>=2)。即在一组勾股数中,当最小边为偶数的时候,它的平方和刚刚好等于两个连续整数之和的两倍。

证明:(x2)/2 = 2n2 = (n2 - 1) + (n2 + 1), 易知 (2n)2 + (n2 - 1)2 = (n2 + 1)2;


勾股数法则:x = m2 - n2, y = 2mn, z = m2 + n2.(m > n)

证明:x2 = m4 - 2m2 * n2 + n4, y2 = 4m2 * n2, z2 =m4 + 2m2 * n2 + n4,易得 x2 + y2 = z2.

 

顺便提一下勾股数通解公式。取定 x (x >= 3)的值后,如果k能使 y = (x2 - k2)/2k为整数,z = y + k,则x,y,z必是勾股数。

这里,使上式中的(x2 - k2) / 2k的值恒为整数的k条件是:

  若 x ≥3 且为奇数,在 x标准分解因数(包括1)全排列重组乘积中,取小于x的因数积为k。如x=15, 152 = 1 * 32 * 52, k = 1, 3, 5, 32.

  若 x ≥4 且为偶数,在 x2 准分解因数(包括1)中去掉一个2后为有效因数,在有效因数全排列重组乘积中,取小于x偶数因数积为k。 如x=10, 102 = 1 * 22 * 52, k = 2.

 

勾股数再生公式。a2 + b2 = c2,那么 x = 2(a + c) + b, y = 2(b + c) + a, z = 2(a + b) + 3c, 那么x2 + y2 = z2.

 

上面的各种法则中,明显是勾股数法则最合适,而且还可以将N从10^6降到10^3,这样想怎样暴力都没问题了。不过勾股数法则并不能表示所有的勾股数对,例如9, 12, 15 就没办法找出对应的 m 和 n,但是幸好这个特例是不是互质的,那我们是不是可以勾股数法则可以求出所有的质勾股数,勾股数法会遗漏掉的是m,n为分数的情况和m,n为无理数的情况,接下来分别讨论这两种情况。

  ①假设m,n是分数,分别取m/a和n/b (a,b,m,n均为整数, m/a和n/b都是最简分数,且m/a > n/b),所以x = (m/a)2 - (n/b)2, y = 2mn/ab,z =(m/a)2 + (n/b)2,所以 x + y = 2(m/a)2,因为x和y都是整数,又a2 != 2,所以2(m/a)2显然不是整数,所以矛盾了,该假设不成立。

  ②假设m和n是无理数。分别取m * sqrt(a), n * sqrt(b) ( a,b,m,n均为整数, a和b均无法提取出整数 ,且m * sqrt(a) > n * sqrt(b) )。x = m2 * a - n2 * b, y = 2mnab, z = m2 * a + n2 * b, 因为y是整数,所以a = b,不然y就不是有理数了。所以x = a * (m2 - n2), y = a * 2mna, z = a * (m2 + n2).显然x,y,z不是互质的。

综上所述,勾股数法则可以求出所有的质勾股数。同时,当我们将质勾股数乘以k倍的时候,可以得到当m和n是无理数的时候遗漏所有勾股数。

 

做到这里程序基本就可以过了,但关于m和n的取值还可以进一步优化。当m和n奇偶性相同的时候,所以可以不用考虑。

令gcd(m,n) = d,当d != 1时,x = m2 - n2可以整除d2, y = 2mn可以整除d2,所以gcd(x,y) = d2,所以也可以不用考虑。


接下来是代码

#include<cstring>
#include<iostream>
using namespace std;
const int MAXN = 1000 + 5;

int cnt;
int N, p;
int a, b, c;
int vis[MAXN * MAXN];

int gcd(int x, int y)
{
    return y == 0 ? x : gcd(y, x % y);
}

int main()
{
    cin.sync_with_stdio(false);

    while(cin >> N)
    {
        cnt = p = 0;
        memset(vis, 0, sizeof(vis));

        for(int n = 1; n * n <= N; ++ n)
            for(int m = n + 1; (c = n * n + m * m) && c <= N; ++ m)

                //m和n同奇偶,那么a,b,c都会是偶数
                if((m & 1) + (n & 1) == 1 && gcd(m, n) == 1)
                {
                    ++cnt;
                    b = (m * n) << 1;
                    a = m * m - n * n;

                    for(int k = 1; c * k <= N; ++k)
                        vis[k * a] = vis[k * b] = vis[k * c] = 1;
                }

        for(int i = 1; i <= N; ++ i)
            if(vis[i] == 0)
                ++p;

        cout << cnt << ' ' << p << endl;
    }

    return 0;
}
View Code

 

 

posted @ 2014-06-04 20:20  Tank..  阅读(287)  评论(0编辑  收藏  举报