题意:(如下)
Multiple query, for each n, you need to get
n i-1
∑ ∑ [gcd(i + j, i - j) = 1]
i=1 j=1
思路:
在求解 ans_n 时,首先我们考虑小于 n 的 i, 我们要check 如题意满足的 gcd(a, b) 是否为1,也就是 a 跟 b 是否互质
也就是对于 i 我们要找满足 (a+b=2*i)&& (a b互质) 的对数,
这时我们需要一个规律:a与b互质,那么 a,b 分别与 (a+b)互质,这样的话我们求满足 i 的条件的对数的时候,只要求 phi[ 2*i ] (欧拉函数) ÷ 2 就好了,,求ans_n的话 就是求前缀和
证一下: 若a与b互质,那么 a,b 分别与 (a+b)互质 :
先假设 a 与 (a+b) 不互质,那么令他们的gcd = t, a=t*x, (a+b) = t*y
那么 b = t*y - t*x = t * (y-x) ,这样 a,b就会有公因子 t ,矛盾,所以 a 与 (a+b) 互质
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 4e7 + 7;
const int maxd = 2e7 + 7;
const int mod = 998244353;
int phi[maxn], prim[maxn];
void get_ouler(int n) {
memset(phi, 0, sizeof phi);
phi[1] = 1;
int id = 0;
for(int i = 2; i < n; ++i) {
if(!phi[i]) {
phi[i] = i - 1;
prim[id++] = i;
}
for(int j = 0; j < id && prim[j]*i < maxn; ++j) {
if(i % prim[j]) {
phi[i*prim[j]] = phi[i] * (prim[j]-1);
} else {
phi[i*prim[j]] = phi[i] * prim[j];
break;
}
}
}
}
ll sum[maxn];
void init() {
sum[1] = 0;
for(int i = 2; i < maxd; ++i) {
sum[i] = phi[i*2]/2;
sum[i] += sum[i-1];
}
}
int main() {
get_ouler(maxn);
init();
int T; scanf("%d", &T);
while(T--) {
ll n; scanf("%lld", &n);
printf("%lld\n", sum[n]);
}
return 0;
}