题目大意:
这题是P2522 的升级版.
T T T组询问,每组询问 n , m n,m n,m点对中有多少个点对满足 g c d ( i , j ) gcd(i,j) gcd(i,j)为质数.
题目思路:P2522+换元+线性筛积性函数
1.前面部分直接按P2522推导即可。
但是直接算的复杂度为: O ( T ∗ π ( n ) ∗ n ) O(T*\pi(n)*\sqrt{n}) O(T∗π(n)∗n).无法接受。观察式子:
2. 原 式 = ∑ k ∈ p n ∑ d = 1 n d μ ( d ) ⌊ n k d ⌋ ⌊ m k d ⌋ 原式=\sum_{k\in p}^{n}\sum_{d=1}^{\frac nd}\mu(d)\lfloor\frac n{kd}\rfloor\lfloor\frac m{kd}\rfloor 原式=∑k∈pn∑d=1dnμ(d)⌊kdn⌋⌊kdm⌋
令 T = k d T=kd T=kd,枚举 T T T.
= ∑ T = 1 n ⌊ n T ⌋ ⌊ m T ⌋ ∑ k ∣ T , k ∈ p μ ( T k ) =\sum_{T=1}^{n}\lfloor\frac n{T}\rfloor\lfloor\frac m{T}\rfloor\sum_{k|T,k\in p}^{}\mu(\frac Tk) =∑T=1n⌊Tn⌋⌊Tm⌋∑k∣T,k∈pμ(kT)
令 f ( T ) = ∑ k ∣ T , k ∈ p μ ( T k ) = μ ∗ 1 ( 素 数 意 义 上 的 ) f(T)=\sum_{k|T,k\in p}^{}\mu(\frac Tk)=\mu*1(素数意义上的) f(T)=∑k∣T,k∈pμ(kT)=μ∗1(素数意义上的).
自然考虑线性筛:
{ f ( i ) = μ ( 1 ) , i ∈ p r i m e f ( i ∗ p j ) = μ ( i ) , i ≡ 0 ( m o d p j ) f ( i ∗ p j ) = − f ( i ) + μ ( i ) , i ≠ 0 ( m o d p j ) \left\{\begin{matrix} f(i)=\mu(1)\ \ \ \ ,i\in prime\\ f(i*p_j)=\mu(i)\ \ \ \ ,i\equiv 0(mod\ \ p_j)\\ f(i*p_j)=-f(i)+\mu(i)\ \ \ \ ,i\neq 0(mod\ \ p_j) \end{matrix}\right. ⎩⎨⎧f(i)=μ(1) ,i∈primef(i∗pj)=μ(i) ,i≡0(mod pj)f(i∗pj)=−f(i)+μ(i) ,i=0(mod pj)
推导:
1.当
i
∈
p
r
i
m
e
i\in prime
i∈prime,①显然成立。(带进式子看看即可)
2.当
i
≡
0
(
m
o
d
p
j
)
i\equiv 0(mod\ \ p_j)
i≡0(mod pj),
i
∗
p
j
i*p_j
i∗pj相较于
i
i
i没有增加本质不同的质数。则:
f
(
i
∗
p
j
)
=
∑
k
∣
i
,
k
∈
p
μ
(
i
∗
p
j
k
)
f(i*p_j)=\sum_{k|i,k\in p}^{}\mu(\frac {i*p_j}k)
f(i∗pj)=∑k∣i,k∈pμ(ki∗pj)当且仅当
k
=
p
j
k=p_j
k=pj时,
μ
\mu
μ函数才有可能不为0(因为
i
∗
p
j
i*p_j
i∗pj的
p
j
p_j
pj的指数
≥
2
\geq2
≥2).这时就要看
i
i
i中有无重复质因子。即
f
(
i
∗
p
j
)
=
μ
(
i
)
f(i*p_j)=\mu(i)
f(i∗pj)=μ(i).
3.当 i ≠ 0 ( m o d p j ) 时 g c d ( i , p j ) = 1 i\neq 0(mod\ \ p_j)时gcd(i,p_j)=1 i=0(mod pj)时gcd(i,pj)=1.则 f ( i ∗ p j ) = ∑ k ∣ ( i ∗ p j ) , k ∈ p μ ( i ∗ p j k ) = μ ( i ) + ∑ k ∣ i , k ∈ p μ ( i k ∗ p j ) f(i*p_j)=\sum_{k|(i*p_j),k\in p}^{}\mu(\frac {i*p_j}k)=\mu(i)+\sum_{k|i,k\in p}^{}\mu(\frac ik*p_j) f(i∗pj)=∑k∣(i∗pj),k∈pμ(ki∗pj)=μ(i)+∑k∣i,k∈pμ(ki∗pj)
= ∑ k ∣ ( i ∗ p j ) , k ∈ p μ ( i ∗ p j k ) = μ ( i ) + μ ( p j ) ∑ k ∣ i , k ∈ p μ ( i k ) =\sum_{k|(i*p_j),k\in p}^{}\mu(\frac {i*p_j}k)=\mu(i)+\mu(p_j)\sum_{k|i,k\in p}^{}\mu(\frac ik) =∑k∣(i∗pj),k∈pμ(ki∗pj)=μ(i)+μ(pj)∑k∣i,k∈pμ(ki)
= − f ( i ) + μ ( i ) =-f(i)+\mu(i) =−f(i)+μ(i)
所以直接筛了。
回到原式,我们预处理完 f f f函数前缀和之后就可以直接二维数论分块做了。
时间复杂度: O ( T n ) O(T\sqrt{n}) O(Tn)
AC代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair<int,int>
#define pb push_back
#define mp make_pair
#define vi vector<int>
#define vll vector<ll>
#define fi first
#define se second
const int maxn = 1e7 + 5;
const int mod = 1e9 + 7;
int a[maxn];
int u[maxn] , bk[maxn] , p[maxn] , cnt;
ll f[maxn];
void init ()
{
u[1] = 1;
for (int i = 2 ; i < maxn ; i++){
if (!bk[i]){
p[++cnt] = i;
u[i] = -1;
f[i] = 1;
}
for (int j = 1 ; j <= cnt && i * p[j] < maxn ; j++){
bk[i * p[j]] = 1;
if (i % p[j] == 0) {
u[i * p[j]] = 0;
f[i * p[j]] = u[i];
break;
}else {
u[i * p[j]] = -u[i];
f[i * p[j]] = -f[i] + u[i];
}
}
}
for (int i = 1 ; i < maxn ; i++) f[i] += f[i - 1];
return ;
}
ll solve (int n , int m){
ll ans = 0;
for (int l = 1 , r ; l <= n ; l = r + 1){
r = min(n / (n / l) , m / (m / l));
ans += 1ll * (f[r] - f[l - 1]) * (n / l) * (m / l);
}
return ans;
}
template <typename T>
void read(T & x){ x = 0;T f = 1;char ch = getchar();while(!isdigit(ch)){if(ch == '-') f = -1;
ch = getchar();}while (isdigit(ch)){x = x * 10 + (ch ^ 48);ch = getchar();}x *= f;}
template <typename T>
void write(T x){if(x < 0){putchar('-');x = -x;}if (x > 9)write(x / 10);putchar(x % 10 + '0');}
int main()
{
init();
int t; read(t);
while (t--){
int n , m; read(n);read(m);
if (n > m) swap(n , m);
printf("%lld\n" , solve (n , m));
}
return 0;
}