勾股数:可以构成一组直角三角形边长的三个正整数。
eg: 3 4 5
勾股数的规律:
1)任何大于1的正奇数a=2k+1,其平方t=a^2仍为奇数,且将平方数拆成两个相邻的整数 b = t / 2, c = t / 2 + 1,a,b,c为一组勾股数。
eg: 3 4 5 5 12 13 7 24 25
证明:
2)任意大于2的正偶数a=2*k,b = k^2-1,c = k^2+1,a,b,c为一组勾股数.
eg:4 3 5 6 8 10 8 15 17
证明:同1)a^2 + b^2 = c^2 代入k即可.
3)毕达哥拉斯三元组
不定方程x^2 + y^2 = z^2.的一组正整数解(x,y,z)称为毕达哥拉斯三元组。
若gcd(x,y,z)=1,则称为本原的毕达哥拉斯三元组。
定理:
正整数x,y,z构成一个本原的毕达哥拉斯三元组且y为偶数,当且仅当存在互素的正整数m,n(m>n),其中m,n的奇偶性不同,
并且满足:x=m2-n2,y=2mn, z=m2+n2。
4)由1)可知直角三角形短直角边为大于1的奇数,另一条直角边与斜边是两个连续自然数。
5)再由4)可推导如果短直角边为奇数,则直角三角形的周长等于短直角边的平方与其本身的和
例题:
codeforce 368
题意: 给出一个正整数n问是否能够找到另外两个正整数,使得这三个正整数为一组勾股数。可以输出另外两个数字,否则输出-1.
解题思路:性质1,2。
#include
using namespace std;
typedef long long ll;
int main(){
ll n;
while(cin>>n){
if(n==1||n==2){
puts("-1");
continue;
}
if(n&1){
cout<<n*n/2<<' '<<n*n/2+1<<endl;
continue;
}
else{
n /= 2;
cout<<n*n-1<<' '<<n*n+1<<endl;
continue;
}
}
return 0;
}
HDU 6411 Find Integer
题意:
给出n,a 求不定方程a^n + b^n = c^n 的一组解b,c.(其中b,c>1)
解题:
1)n=0,显然无解
2)n=1,最简单b=a,c=2*a
3)n=2,勾股数同上一题.
4)n>2,费马大定理x^n + y^n = z^n 在(n>2情况下)无解 直接-1
#include
using namespace std;
typedef long long ll;
int main(){
int T;
ll n,a;
scanf("%d",&T);
while(T--){
scanf("%lld%lld",&n,&a);
if(n==0||n>2){
puts("-1 -1");
continue;
}
if(n==1){
printf("%lld %lld\n",a,a<<1);
continue;
}
else{
if(a&1){
printf("%lld %lld\n",a*a/2,a*a/2+1);
}
else{
a /= 2;
printf("%lld %lld\n",a*a-1,a*a+1);
}
}
}
return 0;
}
POJ 1305 Fermat vs. Pythagoras
题意:给出正整数n,求出(x,y,z<=n)满足不定方程 x^2 + y^2 = z^2且gcd(x,y,z)==1的三元组(x,y,z)的个数,同时求出n以内且毕达哥拉斯三元组不涉及的数的个数。
思路:利用性质3,枚举m,n即可。
AC代码:
#include
#include
#include
#include
#include
using namespace std;
const int maxn = 1e6+10;
bool vis[maxn];
int gcd(int a,int b){
return (b==0)?a:gcd(b,a%b);
}
template <typename T>
inline T Max(const T &a,const T &b){
return a>b?a:b;
}
template <typename T>
inline T Min(const T &a,const T &b){
return a<b?a:b;
}
int main(){
int n,up;
while(~scanf("%d",&n)){
for(int i=1;i<=n;++i){
vis[i] = 0;
}
up = (int)sqrt(1.0*n+0.5);
int ans1=0,ans2=0;
//i,j奇偶性一定不同
for(int i=1;i<=up;i+=2){//枚举奇数
for(int j=2;j<=up;j+=2){//枚举偶数
int d = gcd(i,j);
if(d==1){
int a = Max(i,j);
int b = Min(i,j);
int x = a*a-b*b;
int y = 2*a*b;
int z = a*a+b*b;
if(z<=n){
++ans1;
}
else{
continue;
}
for(int k=1;k*z<=n;++k){
vis[x*k] = 1;
vis[y*k] = 1;
vis[z*k] = 1;
}
}
}
}
for(int i=1;i<=n;++i){
if(!vis[i]) ++ans2;
}
printf("%d %d\n",ans1,ans2);
}
return 0;
}