UVa OJ 106

1、这题是道典型的数论题。数论我没有系统学习过,也证不出别人那样严谨的步骤,只能背一下结论。膜拜!

2、摘抄某位ACMer的解法,真的很不错:

数论经典问题:构造本原勾股数组(PPT):a^2+b^2=c^2 , 其中a,b,c两两互质

 1.证明a和b必定一奇一偶,并可以推导出c一定是奇数 。 证明后我们约定a是奇数,b是偶数,c为奇数,但a和b的大小不能确定

2.a^2+b^2=c^2  --->  a^2=c^2-b^2=(c+b)*(c-b)  ,  那么可知(c+b)和(c-b)都是奇数

  然后证明 (c+b)与(c-b)互质,并且两者都是平方数

3.因为(c+b)与(c-b)都是平方数,则

(c+b)=s^2   ;     (c-b)=t^2  ;    ,满足s>t>=1

很容易证明s与t都是奇数,并且两者互质

4.用s和t来表示a,b,c

a=s*t

b=(s*s-t*t)/2

c=(s*s+t*t)/2

有最后得到的这3条式子,我们知道了构建PPT的方法,就是不断枚举两个奇数s和t,只要s和t互质,就可以通过这3条式子得到a,b,c,它们就是一组PPT。得到一组PPT后就不断翻倍得到其他的勾股数组。

 

#include<cstdio>
#include<cstring>
#include<cmath>
int const N=1000010;
int vis[N];
long long gcd(long long a,long long b){
     return b==0?a:gcd(b,a%b);
}
int main(){
   long long n,a,b,c;
   long long count1,count2;
   while(scanf("%lld",&n)==1){
       count1=count2=0;
       memset(vis,0,sizeof(vis));
       long long m=(long long)sqrt(n+0.5);
       for(long long t=1;t<=m;t++)
          for(long long s=t+2;s*t<=n;s+=2){
              if(gcd(s,t)==1){
                 a=s*t;
                 b=(s*s-t*t)/2;
                 c=(s*s+t*t)/2;
                 if(c<=n){
                   count1++;
                   if(!vis[a]){count2++;vis[a]=1;}
                   if(!vis[b]){count2++;vis[b]=1;}
                   if(!vis[c]){count2++;vis[c]=1;}
                 }
                 for(int j=2;c*j<=n;j++){
                   if(!vis[a*j]){count2++;vis[a*j]=1;}
                   if(!vis[b*j]){count2++;vis[b*j]=1;}
                   if(!vis[c*j]){count2++;vis[c*j]=1;}
                 }
              }
          }
         printf("%lld %lld\n",count1,n-count2);
   }
   return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值