题意:
给定一个整数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;
}