若(a, b, c) 三者互质(它们的最大公因数是 1),它们就称为素勾股数。
勾股数的构造:
a = m*m-n*n
b = 2m*n
c = m*m+n*n
若 m 和 n 是互质,而且 m 和 n 其中有一个是偶数,计算出来的 (a, b, c) 就是素勾股数。(若 m 和 n 都是奇数, (a, b, c) 就会全是偶数,不符合互质。)
题意:给定L,求不大于L的勾股数(a,b,c)。
设m>n;
则m【1,sqrt(L)] (Lmax = 1e6 )
遍历m , 求得符合条件的n即可.
for : i 1->sqrt(L)
则 Jmax = sqrt(L-i*i) ;
a: if i<=Jmax && (i&1)==0, 易知 n 可取任意小于i互素的数 ,即oula(i) ;
b:else if i<=Jmax && (i&1) == 1 , 则必须n为小于i互素的偶数,考虑把i的奇数去掉,即i/2。则【1,i/2]为原来的偶数集合。即求[1,i/2]与i互素的元素个数。正难则反,容斥。
设i的素因子有p1,p2,..pk,含有该因子的事件为A1,A2,…Ak。ans = i/2 - (!A1 + !A2 +…+!Ak) + … + (-1)^k(A1A2…Ak) .
其中Ai = (i/2)/pi. AaAb…Af =(i/2)/(papb…pf) dfs(i/2)
c:else if i >Jmax&& i&1==0 , 求不大于j且与i互素的个数。同理容斥原理。dfs(Jmax)
d:else if i>Jmax&& i&1 ==1,求不大于j且与i互素的偶数的个数。dfs(Jmax/2).
实现时用欧拉函数的积性函数特点
#include<algorithm>
#include<iostream>
#include <string>
#include <cstring>
#include <fstream>
#include <vector>
#include <cmath>
using namespace std;
typedef long long ll ;
vector<ll> pri ;
const int maxn = 1000000 ;
bool Pri[maxn+10] ;
ll check_pri[maxn+10] ;
ll phi[maxn+10] ;
ll pri_num = 0;
ll Ans ;
/******************
ll oula(ll n){
ll ans = n ;
for(ll i = 2 ; i*i <= n ; ++i ){
if(n==1) break;
if( !(n%i) ) {
ans = ans/i*(i-1) ;
while(!(n%i)){
n/=i ;
}
}
}
if(n!=1) ans = ans/n*(n-1) ;
return ans ;
}
*******************/
void get_prime(){
Pri[0] = Pri[1] = false ;
phi[1] = 1 ;
for(int i = 2 ;i <= maxn ; ++i) Pri[i] = true ;
for(int i = 2 ; i <= maxn ; ++i){ // 欧拉筛 , 积性函数的欧拉
if(Pri[i]) {
check_pri[pri_num++] = i;
phi[i] = i-1 ;
}
for(int j = 0 ; j < pri_num && i*check_pri[j] <= maxn ; ++j){
Pri[i*check_pri[j]] = false ;
if(i%check_pri[j] == 0){
phi[i*check_pri[j]] = phi[i]*check_pri[j] ;
break;
}
phi[i*check_pri[j]] = phi[i]*phi[check_pri[j]] ;
}
}
}
void prime(ll n){
ll num = 0;
pri.clear() ;
if(Pri[n]) { // 优化
pri.push_back(n) ;
return ;
}
// ll t= (ll)sqrt(n) ;
for(int i = 0 ; i< pri_num && n>1 ; ++i){ // 优化
if(n%check_pri[i]==0){
pri.push_back(check_pri[i]) ;
while(n%check_pri[i]==0){
n/=check_pri[i];
}
if(Pri[n]) {
pri.push_back(n) ;
return ; // 优化
}
}
}
return ;
}
//****************
ll bit( ll n){
ll ans = 0 ;
ll num = pri.size() ;
for(ll i = 0 ; i < (1<<num) ; ++i){
ll tmp = 1;
ll cnt = 0;
for(ll j = 0 ; j < num ; ++j){
if(i&(1<<j))
tmp *= pri[j] , cnt++ ;
}
if(cnt&1) ans -= n/tmp;
else ans += n/tmp ;
}
return ans ;
}
//***************/
/*************
void dfs(ll pos , ll len , ll val , ll n){
if(pos == pri.size()){
if(len&1){
Ans -= n/val ;
}
else {
Ans += n/val ;
}
return ;
}
dfs(pos+1,len,val,n) ;
dfs(pos+1,len+1,val*pri[pos],n) ;
}
**************/
int main(){
ll l ;
int t ;
cin >> t ;
get_prime() ;
while(t--){
scanf("%lld",&l) ;
Ans = 0;
for(ll i = 1 ; i*i <= l ; ++i){
ll tmp = i*i ;
ll j = (ll)(sqrt(l-tmp)) ;
if(i&1){
prime(i) ;
if(i <= j ){
// dfs(0,0,1,i>>1) ;
Ans+= bit(i>>1) ;
}
else {
// dfs(0,0,1,j>>1) ;
Ans+=bit(j>>1) ;
}
}
else {
if(i <= j){
Ans += phi[i] ;
}
else {
prime(i) ;
// dfs(0,0,1,j) ;
Ans += bit(j) ;
}
}
}
printf("%lld\n",Ans) ;
}
return 0;
}