毕达哥拉斯三元组的解

对于一个方程: x^2 + y^2 = z^2,他两两互质的正整数解满足一下条件

1. x = 2*m*n ,y = m^2 - n^2 ,z = m^2 + n^2

2. gcd( m , n) =1, m > n , m 与 n 的奇偶性不同

( 2*m*n )^2 + ( m^2 - n^2 )^2 = ( m^2 + n^2 )显然成立。

下面我们来看一个例题 POJ 1305 传送门

题意:

给定一个n,然后求满足上面那个方程的解的个数以及不满足勾股数的个数。

分析:

题目的数据范围比较小z^2的范围最大为1e6,因此我们可以直接根据奇偶性来

枚举。

代码如下:

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;

const int maxn = 1e6+10;

int gcd(int a,int b){
    if(b) return gcd(b,a%b);
    return a;
}

int n;
bool vis[maxn];

void solve(){
    memset(vis,0,sizeof(vis));
    int ans1=0,ans2=0;
    for(int i=1;i*i<=n;i++){
        for(int j=2;j*j<=n;j+=2){
            if(gcd(i,j)==1){
                int l=i,r=j;
                if(l>r) swap(l,r);
                if(l*l+r*r<=n){
                    ans1++;
                    vis[2*r*l]=1;
                    vis[r*r-l*l]=1;
                    vis[l*l+r*r]=1;
                }
                int x = 2*l*r;
                int y = -l*l+r*r;
                int z = l*l+r*r;
                for(int k=2;k*z<=n;k++)
                    vis[k*x]=1,vis[k*y]=1,vis[k*z]=1;
            }
        }
    }
    for(int i=1;i<=n;i++)
        if(!vis[i]) ans2++;
    printf("%d %d\n",ans1,ans2);
}

int main()
{
    while(~scanf("%d",&n)){
        solve();
    }
    return 0;
}

例题二:HDU3939 Sticks and Right Triangle
传送门

题意:

题意很简单就是求小于n的满足那个方程的解的个数,但是与上题不同的是这题的

数据范围比较大,l<=1e12,如果直接暴力求解的话肯定会超时。

分析:

首先我们先确定一下m,n的大致范围 m<=sqrt(l-1) n <= sqrt(l - m*m) = t。

然后我们还是只能枚举m.(m > n)我们分成以下两种情况来考虑。

1)m为偶数:

如果 m <= t 那么 n的可能选择就是 phi[m] 表示1~m中与m的互质的数的个数。

如果 m > t 那么 我们可以对m素因子分解,然后通过容斥原理计算1~t内与m

互质的数的个数也就是n的可能选择的方案数。

2)m为奇数:

这种情况下我们需要考虑一下我们需要的是奇偶性与m不相同的且与m互质的n的个

数。

如果 m <= t 那么 n的可能选择就是区间1~m/2内与m互质的数的个数。

如果 m  > t 那么 n的可能选择就是
区间1~t/2内与m互质的数的个数。

因为1~m/2之内的与m互质的数只要乘一个2就转化到了区间1~m且仍与m互质。

代码如下:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>

using namespace std;

typedef long long LL;

const int maxn = 1e6+10;

int phi[maxn];
int prime[maxn],cnt,num;
LL ans ;
LL f[100];
bool vis[maxn];

void init(){//筛法求1e6以内的素数和欧拉函数
    cnt = 0;
    memset(vis,0,sizeof(vis));
    for(int i=2;i<maxn;i++){
        if(!vis[i]){
            prime[cnt++]=i;
            for(int j=i+i;j<maxn;j+=i) vis[j]=1;
        }
    }
    for(int i=0;i<maxn;i++)phi[i]=i;
    for(int i=2;i<maxn;i+=2) phi[i]>>=1;
    for(int i=3;i<maxn;i+=2){
        if(phi[i]==i){
            for(int j=i;j<maxn;j+=i)
                phi[j]=phi[j]-phi[j]/i;
        }
    }
}

void get_factor(int x){//对x进行素因子分解
    num=0;
    for(int i=0;i<cnt&&prime[i]*prime[i]<=x;i++){
        if(x%prime[i]==0){
            f[num++]=prime[i];
            while(x%prime[i]==0) x=x/prime[i];
        }
    }
    if(x>1) f[num++]=x;
}

void dfs(int id,int mul,int tot,int x){//容斥原理求[1,x]内与y互质的数的个数f[]为i的素因子
    if(id==num){
        if(tot&1) ans = ans - x/mul;
        else ans = ans + x/mul;
        return;
    }
    dfs(id+1,mul*f[id],tot+1,x);
    dfs(id+1,mul,tot,x);
}

int main()
{
    init();
    int t;
    scanf("%d",&t);
    while(t--){
        LL l;
        scanf("%I64d",&l);
        int n = sqrt(l+0.5);
        ans = 0;
        for(int i=1;i<=n;i++){//枚举m
            int lim = sqrt(l-(LL)i*i+0.5);
            if(i&1){
                get_factor(i);
                if(i<=lim) dfs(0,1,0,i>>1);
                else dfs(0,1,0,lim>>1);
            }
            else{
                if(i<=lim) ans=ans+phi[i];
                else{
                    get_factor(i);
                    dfs(0,1,0,lim);
                }
            }
        }
        printf("%I64d\n",ans);
    }
    return 0;
}

这题的代码其实还可以优化,我们可以在预处理的时候将1e6之内的数都直接素因子分解

然后再后来调用的时候就可以 O(1)的查询了。

时间: 2024-07-31 16:55:27

毕达哥拉斯三元组的解的相关文章

POJ 1305-Fermat vs. Pythagoras(毕达哥拉斯三元组的解)

题目地址:POJ 1305 题意:给一个整数N,求N范围内的本原的毕达哥拉斯三元组的个数,以及N以内毕达哥拉斯三元组不涉及数的个数. 思路: 首先我们先来了解一下一些基本的定义 毕达哥拉斯三元组: 设不定方程:x^2+y^2=z^2若正整数三元组(x,y,z)满足上述方程,则称为毕达哥拉斯三元组. 本原毕格拉斯三元组: 在毕格拉斯三元组的基础上,若gcd(x,y,z)=1,则称为本原的毕达哥拉斯三元组. 定理: 正整数x,y,z构成一个本原的毕达哥拉斯三元组且y为偶数,当且仅当存在互素的正整数m

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

题意:(a, b, c)为a2+b2=c2的一个解,那么求gcd(a, b, c)=1的组数,并且a<b<c<=n,和不为解中所含数字的个数,比如在n等于10时,为1, 2, 7,9则输出4. 好了!把所用知识点说一下: 数论之勾股数组(毕达哥拉斯三元组) 本原勾股数组(a,b,c)(a为奇数,b偶数)都可由如下公式得出:a=st,b=(s2-t2)/2, c = (s2+t2)/2, 其中s>t>=1是没有公因数的奇数. 再把勾股数公式拿过来: 套路一: 当a为大于1的奇数

FZU1669 Right-angled Triangle【毕达哥拉斯三元组】

题目链接: http://acm.fzu.edu.cn/problem.php?pid=1669 题目大意: 求满足以a.b为直角边,c为斜边,并且满足a + b + c <= L的直角三角形的个数. 思路: 勾股定理,a.b.c也就是本原毕达哥拉斯三元组,则满足: x = m^2 - n^2 y = 2*m*n z = m^2 + n^2 其中m > n,且若m为奇数,则n为偶数,若m为偶数,则n为奇数. 枚举m.n,然后将三元组乘以i倍,保证 i * (x + y + z)在所给范围内(2

POJ1305 Fermat vs. Pythagoras【毕达哥拉斯三元组】

题目链接: http://poj.org/problem?id=1305 题目大意: 给一个整数N,求N范围内的本原的毕达哥拉斯三元组的个数,以及N以内毕达哥拉斯三元组不涉及 数的个数. 思路: 本原毕达哥拉斯三元组x^2 + y^2 = z^2 满足 x = m^2 - n^2,y = 2*m*n,z = m^2 + n^2,其 中m > n,且若m为奇数,则n为偶数,若m为偶数,则n为奇数.要求所给范围N内的本原毕达哥拉 斯三元数组,只需枚举m.n,然后将三元组x.y.z乘以i(保证i*z在

Python练习题 037:Project Euler 009:毕达哥拉斯三元组之乘积

本题来自 Project Euler 第9题:https://projecteuler.net/problem=9 # Project Euler: Problem 9: Special Pythagorean triplet # A Pythagorean triplet is a set of three natural numbers, # a < b < c, for which, a**2 + b**2 = c**2 # For example, 3**2 + 4**2 = 9 +

Project-Euler problem 1-50

最近闲的做了下Project Euler 上的题目,前面50题都比较简单,简单总结下.代码一般是Python和C/C++的 用Python 做这些题目简直是酸爽啊 一下代码可能不一定是我的,因为不知道论坛里面的回复不是永久的,所以我的代码有的丢了,可能找个和我的意思相近的代码.题目翻译是从 欧拉计划 | Project Euler 中文翻译站上面Copy 的表告我. Problem 1  Multiples of 3 and 5 10以下的自然数中,属于3和5的倍数的有3,5,6和9,它们之和是

erlang_base01_语法

##erlang学习总结 ###1.退出,输入 haut(). ###2.-module ###3.module_name:function_name( arguments ) 例如调用tut:double(10),说明调用tut模块的double函数. ###4.模块名为tut -module(tut). -export( [double/1, fact/1] ). double(X)-> 2 * X. fact(1) -> 1; fact(N) -> N*fact(N-1). 分号表

同余方程,不定方程总结

听说这是数论中比较重要的部分了,一点点的总结吧.. 一.线性同余方程与不定方程: 单个一元线性方程 求解方法:扩展欧几里得 exgcd 模板: long long exgcd(long long a,long long b,long long &x,long long &y) { if(!b) { x=1; y=0; return a; } __int64 tt=exgcd(b,a%b,x,y); __int64 t; t=x; x=y; y=(t-a/b*y); return tt; }

fibonacci数列为什么那么重要,所有关于数学的书几乎都会提到?【转自知乎】

转自知乎王希的回答.原文链接:http://www.zhihu.com/question/28062458/answer/39763094 一句话先回答问题:因为斐波那契数列在数学和生活以及自然界中都非常有用. 下面我就尽我所能,讲述一下斐波那契数列. 一.起源和定义 斐波那契数列最早被提出是印度数学家Gopala,他在研究箱子包装物件长度恰好为1和2时的方法数时首先描述了这个数列.也就是这个问题: 有n个台阶,你每次只能跨一阶或两阶,上楼有几种方法? 而最早研究这个数列的当然就是斐波那契(Le