题意:
给定一个整数L(L<=1e12),计算(x,y,z)组的个数。其中x<y<z,x^2+y^2=z^2,gcd(x,y)==1,gcd(x,z)==1,gcd(y,z)==1。
题解:
在做题之前先要了解下勾股数:勾股数-维基百科
以下的方法可用来找出勾股数。设 m > n 、 m 和 n 均是正整数,
a = m^2 − n^2,
b = 2*m*n,
c = m^2 + n^2
那么a^2+b^2=c^2
若 m 和 n 是互质,而且 m 和 n 其中有一个是偶数,计算出来的 a, b, c 就是素勾股数,即符合题意的勾股数。(若 m 和 n 都是奇数, a, b, c 就会全是偶数,不符合互质。)
实际情况是我们枚举所有的m(1<=m<=sqrt(L)),从而可以通过j=sqrt(L-i*i),确定n的范围为[1,j],i为枚举的m。然后分情况讨论:
i为偶数:
由于i为偶数,而要求i和j互质,所以j必定是奇数,所以就符合了一奇一偶的要求。
i为奇数:1)i<=j,由于m>n,所以符合条件的个数有phi[i]个(phi[i]为欧拉函数,表示小于i且与i互质的个数),
2)i>j,我们分解i得到所有i的质因子ci,假设有三个质因子,由容斥原理得到fun(j)=j-(j/c1+j/c2+j/c3)+(j/(c1*c2)+j/(c1*c3)+j/(c2*c3))-(j/(c1*c2*c3))。
由于i为奇数,所以根据要求j必须为偶数。
1)i<=j,由于m>n,所以结果是fun[i/2]。why?因为要保证m为偶数,fun(i/2)表示小于等于i/2的数与i互质的个数,我们记为ai,那么2*ai就是小于i的,与i互质的偶数了;那么还有没可能存在更多的个数呢?
我们来反证下:假设存在一个偶数c,gcd(c,i)==1且c/2不在fun(i/2)范围内。那么gcd(c/2,i)!=1,这与gcd(c,i)==1矛盾。所以至多存在fun(i/2)个偶数c,使得gcd(c,i)==1。
2)i>j,同理,结果为fun[j/2]。
其中容斥定理我们可以用dfs解决。
注意:下面的代码我是初始化所有1e6以内的数的质因子,这是以空间换时间;如果想节约空间,可以每次用到一个数的质因子的时候再求。
代码:
#include <cstdio> #include <cstring> #include <cmath> #include <cstdlib> #include <iostream> #include <algorithm> #include <queue> #include <map> #include <vector> using namespace std; #define LL __int64 const int maxn=1e6+10; int prime[maxn],check[maxn],tot; int phi[maxn]; int f[maxn][7]; int tt[maxn]; LL ans; void get_prime_factor(int n) { int i=0,m,k=n; tt[n]=0; if(!check[n]) { f[n][tt[n]]=n; tt[n]++; return ; } while(n!=1) { if(n%prime[i]==0) { f[k][tt[k]]=prime[i]; tt[k]++; while(n%prime[i]==0)n=n/prime[i]; if(!check[n]) { if(n!=1) f[k][tt[k]++]=n; return ; } } i++; } } void init()//预处理,找出所有1e7以内的素数,以减少查找1e14范围数的因子的时间 { //现行筛素数的方法,时间复杂度为O(n) memset(check,false,sizeof(check)); int i,j; tot=0; for(i=2;i<maxn;i++) { if(!check[i])prime[tot++]=i; for(j=0;j<tot;j++) { int c=i*prime[j]; if(c>=maxn)break; check[c]=true; if(c==0)break; } } //获得所有数的质因子 for(i=1;i<maxn;i++) { get_prime_factor(i); } } void euler_phi() { int i,j,k; //欧拉函数,phi[i]表示不超过i的与i互质的整数个数 for(i=2;i<maxn;i++)phi[i]=0; phi[1]=1; for(i=2;i<maxn;i++) if(!phi[i]) for(j=i;j<=maxn;j+=i){ if(!phi[j])phi[j]=j; phi[j]=phi[j]/i*(i-1); } } void dfs(int t,int num,int n,int sum,int k) { if(t==tt[k]) { if(num&1)ans-=n/sum; else ans+=n/sum; return ; } dfs(t+1,num,n,sum,k); dfs(t+1,num+1,n,sum*f[k][t],k); } int main() { init(); euler_phi(); int T; scanf("%d",&T); while(T--) { int i,j,k,n,m; LL l; ans=0; scanf("%I64d",&l); n=(int)sqrt(l+0.5); for(i=1;i<=n;i++) { m=(int)sqrt(l-(LL)i*i+0.5); if(i&1) { if(i<=m)dfs(0,0,i>>1,1,i); else dfs(0,0,m>>1,1,i); } else { if(i<=m)ans+=phi[i]; else dfs(0,0,m,1,i); } } printf("%I64d\n",ans); } return 0; }