那么可以发现最后那个对 c 求和的东西对外只和 n/d2 有关系,对内可以数论分块,一脸时间复杂度 O(n3/4) 的模样,复杂度够了,加个记忆化。冲冲冲~
#include<bits/stdc++.h>usingnamespace std;typedeflonglong lld;inlineintsqrtd(int x){int tot =sqrtl(x);while(tot * tot < x) tot++;while(tot * tot > x) tot--;return tot;}inline pair<lld,lld>c(int n){static unordered_map<int,pair<lld,lld>> _C;if(_C.count(n))return _C[n];
lld p1 =0, p2 =0;int m =sqrtd(n);for(int i =1, j = m; i <= m; i++){while(i * i + j * j > n) j--;
p1 += j;if(i &1) p2 +=(j+1)/2;}return _C[n]=make_pair(p1, p2);}inline lld h(int n,bool odd){
lld ans =0;for(int L =1, R; L <= n; L = R+1){
R = n /( n / L );auto cur =c(n/L);
ans +=(R-L+1)* cur.first;if(odd) ans -=(R-L+1)* cur.second;}return ans;}intmain(){constint MAXN =1e6+5;staticint pri[MAXN], pcn;staticchar isnp[MAXN], miu[MAXN];
miu[1]=1;for(int i =2; i < MAXN; i++){if(!isnp[i]) pri[pcn++]= i, miu[i]=-1;for(int j =0; j < pcn && i * pri[j]< MAXN; j++){
isnp[i * pri[j]]=1;if(i % pri[j]==0)break;
miu[i * pri[j]]=-miu[i];}}int T, n;scanf("%d",&T);while(T--){scanf("%d",&n);
lld ans =0;for(int d =1; d * d <= n; d++)if(miu[d]) ans += miu[d]*h(n/d/d, d&1);printf("%lld\n", ans/2);}return0;}