zoukankan      html  css  js  c++  java
  • UVa 106

    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

     

  • 相关阅读:
    HDU 5583 Kingdom of Black and White 水题
    HDU 5578 Friendship of Frog 水题
    Codeforces Round #190 (Div. 2) E. Ciel the Commander 点分治
    hdu 5594 ZYB's Prime 最大流
    hdu 5593 ZYB's Tree 树形dp
    hdu 5592 ZYB's Game 树状数组
    hdu 5591 ZYB's Game 博弈论
    HDU 5590 ZYB's Biology 水题
    cdoj 1256 昊昊爱运动 预处理/前缀和
    cdoj 1255 斓少摘苹果 贪心
  • 原文地址:https://www.cnblogs.com/tank39/p/3911405.html
Copyright © 2011-2022 走看看