「整理」勾股数组

Posted louhancheng

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了「整理」勾股数组相关的知识,希望对你有一定的参考价值。

我们大概老早就知道勾股定理,它大概就长这样:
[a^2+b^2=c^2]
嗯,的确够简单的。

而且我们清楚地知道它的一个基本应用——知道(RtDelta)的两边长,求第三边。这大概初一就学了。

对于不知道勾股定理的童鞋们,不了解没关系,因为这里没有三角形,也不是探讨怎么求第三边,我们只探讨勾股数组。

这里的(a equiv b(mod c))其实就是(a\%c=b\%c),a|b其实就是(b\%a=0),希望小白们不要看不懂。

如果真的看不懂,可以先学习同余、约数、素数的知识。


勾股数组

什么事都得从定义开始。来看看百度百科教会我们什么。

定义——勾股数组

一般地,若三角形三边长a,b,c都是正整数,且满足a,b的平方和等于c的平方,那么数组(a,b,c)称为勾股数组。勾股数组是人们为了解出满足勾股定理不定方程的所有整数解而创造的概念。

嗯,够简单的。不过有些人总是喜欢把它弄得高大尚些,把它叫做“毕达哥拉斯三元组”,其实是一个玩意儿,只是后者听起来更加牛。这不必深究,知道它就是勾股数组即可。而勾股数组也就是把三个数a,b,c((a^2+b^2=c^2))用小括号括起来而已。很简单吧?我们举几个栗子——

a b c
3 4 5
5 12 13
6 8 10
7 24 25

诶,(3,4,5)、(6,8,10)看着好像!emmm

实际上它们的本质都是勾三股四弦五 这样就不好玩了嘛)很明显,如果一个勾股数组中每个数同乘一个正整数,得到的三元组还是一个勾股数组。It‘s very easy.我们设三元组(a,b,c)是勾股数组,d是一个正整数。

(ecause (a,b,c) ext{是勾股数组})
( herefore a^2+b^2=c^2)
( herefore d^2 imes a^2+d^2 imes b^2=d^2 imes c^2)
( herefore (d imes a)^2+(d imes b)^2=(d imes c)^2)
( herefore (da,db,dc) ext{为勾股数组})

所以说,勾股数组有无穷个。

为了更有趣,我们还要引入本原勾股数组的概念。不过很遗憾,百度百科词条里没有。

定义——本原勾股数组

本原勾股数组(简写为PPT)是一个三元组(a,b,c),其中a,b,c没有公因数,且满足(a^2+b^2=c^2)

——摘自Joseph H. Silverman《A Friendly Introduction To Number Theory》

插句小广告,这本书对于学习数论还是很不错的,中文译名为《数论概论》。

给出一些本原勾股数组。

(3,4,5)(5,12,13)(8,15,17)(7,24,25)......

来看看它有啥性质。

1.a、b为一奇一偶,c为奇数

证明:我们分类探讨。

当a、b均为偶数时,c必然为偶数,它显然不是一个本原勾股数组,a、b、c有公因数2。

当a、b均为奇数时,c必然为偶数,设(a=2x+1,b=2y+1,c=2z)

(a^2+b^2=(2x+1)^2+(2y+1)^2=4x^2+4x+1+4y^2+4y+1=4(x^2+y^2+x+y)+2)
(c^2=(2z)^2=4z^2)
(4(x^2+y^2+x+y)+2=4z^2)
(2(x^2+y^2+x+y)+1=2z^2)
(ecause 2(x^2+y^2+x+y)+1equiv 1(mod 2))
(2z^2equiv 0(mod 2))
( ext{很明显,}2(x^2+y^2+x+y)+1 ext{与}2z^2 ext{奇偶性不同。})
( herefore ext{不成立})
证明完毕.

2.(a equiv 0(mod 3) ext{或}b equiv 0(mod 3))

这里感谢@LJC00118Rank1奆佬教会我如何证明。这里声明一下,我绝对没有照搬照抄)

我们先证明另外一个定理:(a^2\%3=0 ext{或}1)

证明:(a=3x+i(i=0,1 ext{或}2))

当i=0时,定理显然成立。

当i=1时,(a^2=(3x+1)^2=9x^2+6x+1=3(3x^2+2x)+1),所以(a^2\%3=1)

当i=2时,(a^2=(3x+2)^2=9x^2+12x+4=3(3x^2+4x+1)+1),所以(a^2\%3=1)

证明完毕.

继续证明原来的定理(a equiv 0(mod 3) ext{或}b equiv 0(mod 3))

证明:假设该定理不成立,
(a ot= 0 ext{且}b ot=0)
(ecause a\%3 ot=0)
( herefore a^2\%3 ot=0 ext{……由上述证明可知})
(ecause a^2\%3=0 ext{或}1)
( herefore a^2\%3=1)
( ext{同理得},b^2\%3=1)
( herefore(a^2+b^2)\%3=2)
( herefore c^2\%3=2)
这与(c^2\%3=0 ext{或}1)矛盾,因此该定理成立
值得一提的是,这个定理适用于所有勾股数组。不管是本原勾股数组还是其他勾股数组。


我们暂时抛开更多其他的定理,来探讨如何求本原勾股数组。壹是主要部分)

为了方便,我们认为本原勾股数组(a,b,c)中,a为奇数,b为偶数,c为奇数。

(a^2+b^2=c^2)
(a^2=c^2-b^2=(c+b)(c-b))

我们从这方面考虑。(c+b)与(c-b)不应该存在>1的公约数。

证明:

( ext{设}d|(c+b) ext{且}d|(c-b))
( ext{则}d|(c+b+c-b),d|(2c))
(d|(c+b-c+b),d|(2b))
(d^2|a^2 ext{即}d|a)
(ecause c\%2=1,b\%2=0)
( herefore (b+c)\%2=1)
( herefore d ext{不可能为偶数,否则}d|(c+b) ext{不成立})
( herefore d|b,d|c)
(ecause (a,b,c) ext{是本原勾股数组})
( herefore gcd(a,b,c)=1)
( herefore d=1)

额,看到这里,童鞋们快被公式和证明逼疯了吧,坚持一下,答案马上就出现了,胜利就在前方!

我们知道,任何一个大于1的正整数都可以表示成固定几个素数的积,也就是长这模样——

(a=p_1^{k1} imes p_2^{k2} imes p_3^{k3} imes p_4^{k4} ext{......})

(a^2)既然为平方数,那么如果把(a^2)分解质因数,对于任意ki,都有(ki equiv0(mod 2))

前面提过,gcd((c+b),(c-b))=1,所以如果(p_1|(c+b))(p_1|(c-b))是不可能成立的。

我们暂时抛开繁琐的证明,尝试想象。假设你的手里有一个数(a^2)。看看能不能把它分解成2个没有公因数的数。

啊,不错,分成的这两个数就是(c+b)与(c-b)。要怎么分呢?我们举个栗子。试试分解(10^2)?

先分解质因数。(10^2=2^2 imes 5^2)

我们选取一些质数给(c+b),剩下的质数全部给(c-b) (color{red} ext{值得注意的是,我们仅探讨正整数范围内,分解要满足(c+b)>(c-b)})

嗯,这好像只有一种分法( o c-b=2^2,c+b=5^2)

大家可以自己再选几个数,动手尝试。我们可以发现,(c-b)如果含有质因数p,(c-b)肯定也含有质因数(p^2)(c+b)也是如此。所以,((c-b))((c+b))一定是完全平方数。

来吧,冲向胜利!

我们设(s^2=c+b,t^2=c-b(s>b))

我们把上面俩式子加一加、减一减——哇!

(2c={s^2+t^2},c=frac {s^2+t^2}2)
(2b={s^2-t^2},b=frac {s^2-t^2}2)

(ecause a^2=(c+b) imes(c-b))
( herefore a^2=s^2 imes t^2)
( herefore a=st)

TQL!

勾股数组定理

每个本原勾股数组(a,b,c)(其中a为奇数,b为偶数),都可从如下公式得出。

(large a=st,b=frac {s^2-t^2}2,c=frac {s^2+t^2}2)

其中(s >t ge 0)是任意没有公因数的奇数。

当然,以上证明是不完整的。我们还要证明a、b、c没有公因数。这个要涉及素数的性质,这里不加以探讨。有兴趣的读者可以去了解。

还有一种神奇的方法,已知c,可以在(O(sqrt n))的时间内求出满足(a^2+b^2=c^2)的a、b个数。

由于这里要涉及复数、高斯素数,对初中学历的童鞋不友好,这里放个链接,有兴趣的童鞋可以去了解,顺便切道紫题P2508 [HAOI2008]圆上的整点
不是我不会证QAQ,而是那个链接里的视频讲的比我好多了)
这里给出P2508 [HAOI2008]圆上的整点中我的代码。仅做参考,欢迎前来hack。

#include<bits/stdc++.h>
using namespace std;
#define LL long long

LL R, N, ans(1);

int main(){
    scanf( "%lld", &R ); N = R;
    if ( R == 0 ){ printf( "1
" ); return 0; }
    
    while( R % 2 == 0 ) R >>= 1;
    
    for ( LL i = 3; i * i <= N; i += 2 ){
        LL cnt(0);
        
        while( R % i == 0 ) cnt++, R /= i;
        
        if ( i % 4 == 1 ) ans *= ( cnt * 2 + 1 );
    }
    
    if ( R > 1 && R % 4 == 1 ) ans *= 3;
    
    printf( "%lld", ans << 2 );
    return 0;
}

一些其他性质

这里还是假设本原勾股数组(a,b,c)中,a为奇数。

  1. (c-a=2t^2,t ext{为一整数})

这个证明思路与上面十分相似。只要把(a^2)移到右边instead of (b^2) 即可。

Very easy. 给个开头,请自行证明。当然,这也能在所有勾股数组中适用)
[ b^2=c^2-a^2=(c+a)(c-a) ]
还有两条不常用的性质,了解即可。

  1. (a^4b^4+b^4c^4+c^4a^4=L^2)
  2. (a^8+b^8+c^8=2L^2)

具体应用

不管啥东西学了不用都是没用的。

来看看一道题。

仙人吃肉(gou.pas/c/cpp)

题目描述

by 是一个擅长吃的仙人,既然是仙人嘛,自然对吃的东西有一定的要求,比方说吃牛肉。首先,yyy 是非牦牛肉不吃的,其次,yyy 每次只在 3 头牦牛中选 1 头来吃,并且这三头牦牛的长度还要满足以下条件:不妨设这三头牦牛的长度为 a, b, c(a < b <c) ,则 (a*a+b*b=c*c)。by 养了很多头牦牛,每头牦牛的长度都不大于 N,每种长度的牦牛都有。作为 yyy
弟子的你想知道,一共有多少种不同的方案用来安排给 yyy 准备牦牛肉。即给定一个正整数 N,找出符合 (a*a+b*b=c*c) 的三元组(a,b,c)的总数,其中 a<b<c<=N,

输入数据

输入文件仅有一行包含一个正整数 N。

输出数据

输出文件仅有一行包含一个整数,表示安排食谱的方案总数。

样例

gou.in

10

gou.out

2

样例说明

只有两种方案:a=3,b=4,c=5 或 a=6,b=8,c=10。

数据规模

对于 30%的数据满足:N<=300;
对于 60%的数据满足:N<=20000;
对于 100%的数据满足:N<=1000000。


思路

枚举s、t。根据勾股数组定理,就可以求出c。

这里s=i+j,t=i。

思路十分明了,代码也十分简短。

代码

#include<bits/stdc++.h>
using namespace std;
#define LL long long

int N;
long long ans;

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

int main(){
    scanf( "%d", &N );
    for ( int i = 1; i <= 2000; i += 2 )
        for ( int j = 2; j <= 2000; j += 2 ){
            if ( gcd( i, j ) == 1 ){
                int c( i * i + j * j / 2 + i * j );
                if ( c <= N ) ans += N / c;
                else break;
            } 
        }
    printf( "%lld
", ans );
    return 0;
}

由于我很弱,所以可能会出错,欢迎指正错误QAQ。

今天就讲到这里了,这里骗个赞

以上是关于「整理」勾股数组的主要内容,如果未能解决你的问题,请参考以下文章

勾股数组 学习笔记

Fermat vs. Pythagoras POJ - 1305 (数论之勾股数组(毕达哥拉斯三元组))

IOS开发-OC学习-常用功能代码片段整理

VS2015 代码片段整理

小程序各种功能代码片段整理---持续更新

常用python日期日志获取内容循环的代码片段