莫比乌斯反演入门(五)--P2257(P2522升级)

本文介绍了如何利用P2522问题的思路结合换元和线性筛积性函数技巧,解决计算 gcd(i,j) 为质数的点对问题。通过巧妙转换和线性筛预处理,将时间复杂度从 O(T * π(n) * n) 降低到 O(Tn),实现了高效AC代码实现。
摘要由CSDN通过智能技术生成
题目大意:

这题是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 =kpnd=1dnμ(d)kdnkdm

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=1nTnTmkT,kpμ(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)=kT,kpμ(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)    ,iprimef(ipj)=μ(i)    ,i0(mod  pj)f(ipj)=f(i)+μ(i)    ,i=0(mod  pj)

推导:
1.当 i ∈ p r i m e i\in prime iprime,①显然成立。(带进式子看看即可)

2.当 i ≡ 0 ( m o d    p j ) i\equiv 0(mod\ \ p_j) i0(mod  pj), i ∗ p j i*p_j ipj相较于 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(ipj)=ki,kpμ(kipj)当且仅当 k = p j k=p_j k=pj时, μ \mu μ函数才有可能不为0(因为 i ∗ p j i*p_j ipj p j p_j pj的指数 ≥ 2 \geq2 2).这时就要看 i i i中有无重复质因子。即 f ( i ∗ p j ) = μ ( i ) f(i*p_j)=\mu(i) f(ipj)=μ(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(ipj)=k(ipj),kpμ(kipj)=μ(i)+ki,kpμ(kipj)

= ∑ 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(ipj),kpμ(kipj)=μ(i)+μ(pj)ki,kpμ(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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值