//数论(勾股数组相关),在acdream 群里看到的
实现代码如下:
#include<stdio.h> #include<math.h> #include<string.h> #include<vector> using namespace std; vector<int> fac[1000001]; int prime[100000],phi[1000001],m; void init(){ //预处理phi[]和fac[] int i,j; m=0; for(i=2;i<=1000000;i++){ if(!phi[i]){ phi[i]=i-1; prime[m++]=i; for(j=i+i;j<=1000000;j+=i){ fac[j].push_back(i); } } for(j=0;i*prime[j]<=1000000&&j<m;j++){ if(i%prime[j]==0) phi[i*prime[j]]=phi[i]*prime[j]; else { phi[i*prime[j]]=phi[i]*(prime[j]-1); } } } } long long sum,N; void dfs(vector<int> &F,int s,int dep,int v){ unsigned i; if(dep&1) sum-=N/v; else sum+=N/v; for(i=s;i<F.size();i++){ dfs(F,i+1,dep+1,v*F[i]); } } long long cal(long long M,long long t){ //容斥求小于t且与M互质的个数,fac[M]中保存的为M的质因子; N=t;sum=0; dfs(fac[M],0,0,1); return sum; } long long n; int main(){ int cas; long long k,g,ans,i; init(); scanf("%d",&cas); while(cas--){ scanf("%I64d",&n); k=sqrt((double)(n-1)); if(k*k>n-1) k--; ans=0; for(i=2;i<=k;i++){ g=sqrt((double)(n-i*i)); //保证g*g+i*i<=n if(g>=i-1){ if(i&1) ans+=cal(i,i/2); else ans+=phi[i]; } else { if(i&1) ans+=cal(i,g/2); else ans+=cal(i,g); } } printf("%I64d\n",ans); } return 0; }