UVa 106 - Fermat vs. Pythagoras 素勾股数

来源:互联网 发布:淘宝美工工资怎么算 编辑:程序博客网 时间:2024/04/30 02:08

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(n^2 + n) + 1,所以 (2n+1)^2 = 1 (mod 4).

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

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

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

先假设x和y都为奇数,那么x = 2m + 1, y = 2n + 1,所以 x^2 + y^2 = (2m+1)^2 + (2n+1)^2 = 4(m^2 + n^2 + 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是完全平方数)

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


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

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

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

证明:x^2 = (2n + 1)^2 = 4n^2 + 4n + 1 = (2n^2 + 2n) + (2n^2 + 2n + 1),易知 (2n + 1)^2 + (2n^2 + 2n)^2 = (2n^2 + 2n + 1)^2


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

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


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

证明:x^2 = m^4 - 2(m^2) * (n^2) + n^4, y^2 = 4(m^2) * (n^2), z^2 =m^4 + 2(m^2) * (n^2) + n^4,易得 x^2 + y^2 = z^2.


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

则x,y,z必是勾股数。

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

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

x为≥4的偶数,在x^2标准分解因数(包括1)中去掉一个2后为有效因数,在有效因数全排列重组乘积中,

取小于x偶数因数积为k。 如x=10, 10^2 = 1 * 2^2 * 5^2, k = 2.

勾股数再生公式。a^2 + b^2 = c^2,那么 x = 2(a + c) + b, y = 2(b + c) + a, z = 2(a + b) + 3c, 那么x^2 + y^2 = z^2.


上面的各种法则中,明显是勾股数法则最合适,而且还可以将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都是整数,

又a^2 != 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 = (m^2) * a - (n^2) * b, y = 2mnab, z = (m^2) * a + (n^2) * b,

因为y是整数,所以a = b,不然y就不是有理数了。所以x = a * (m^2 - n^y = a * 2mna, z =a * (m^2 + n^2).

显然x,y,z不是互质的。

综上所述,勾股数法则可以求出所有的质勾股数。同时,当我们将质勾股数乘以k倍的时候,

可以得到当m和n是无理数的时候遗漏所有勾股数。


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

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


接下来是代码


#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;}





0 0