HDU6715 算术(莫比乌斯反演)

别等时光非礼了梦想. 提交于 2019-11-28 19:43:28

HDU6715 算术

莫比乌斯反演的变形。

\(\mu(lcm(i,j))\) 变换,易得 \(\mu(lcm(i,j)) = \mu(i)\cdot\mu(j)\cdot \mu(gcd(i,j))\) 。那么有:
\[\begin{split} \sum_{i=1}^{n} \sum_{j=1}^{m} \mu(lcm(i,j)) &= \sum_{i=1}^{n}\mu(i) \sum_{j=1}^{m}\mu(j)\cdot \mu(gcd(i,j)) \\ &= \sum_{d=1}^{\min(n,m)}\sum_{i=1}^{n/d}\sum_{j=1}^{m/d}\mu(id)\mu(jd)\mu(d)[gcd(i,j)=1] \end{split}\]

由于莫比乌斯函数的性质 \(\sum_{d\ |\ n}\mu(d)=[n=1]\) ,我们有:
\[\begin{split} \text{上式} = \sum_{d=1}^{\min(n,m)}\sum_{d_1 = 1}^{\min(n,m)/d}\sum_{i=1}^{n/dd_1}\sum_{j=1}^{m/dd_1}\mu(idd_1)\mu(jdd_1)\mu(d)\mu(d_1) \end{split}\]

我们令 \(T = dd_1\) ,有:
\[ \text{上式}=\sum_{T=1}^{\min(n,m)}\sum_{d|T}\sum_{i=1}^{n/T}\sum_{j=1}^{m/T}\mu(iT)\mu(jT)\mu(d)\mu(T/d) \]

\(f(T) = \sum_{d|T} \mu(d)\mu(T/d)\)

\(g(T,N,M)=\sum_{i=1}^{N}\sum_{j=1}^{M}\mu(iT)\mu(jT)=(\sum_{i=1}^{N}\mu(iT))\cdot(\sum_{j=1}^{M}\mu(jT))\)

那么我们有:
\[ \text{上式}=\sum_{T=1}^{\min(n,m)} f(T)\cdot g(T,n/T,m/T) \]

\(g(T,n/T,m/T)\) 可以在 \(O(n/T+m/T)\) 的时间内计算。

时间复杂度为 \(O(n\log n)\)

#include<stdio.h>
#include<algorithm>

using namespace std;

const int maxn = 1000005;

int t, n, m, tot;
int mu[maxn], check[maxn], prime[maxn];
long long ans, f[maxn];

void init()
{
    mu[1] = 1; tot = 0;
    for(int i = 2; i <= 1000000; i++){
        if(check[i] == 0){
            mu[i] = -1;
            prime[++tot] = i;
        }
        for(int j = 1; j <= tot && prime[j] * i <= 1000000; j++){
            check[i * prime[j]] = 1;
            if(i % prime[j] == 0) break;
            mu[i * prime[j]] = -1 * mu[i];
        }
    }
    for(int i = 1; i <= 1000000; i++){
        for(int j = 1; j * i <= 1000000; j++){
            f[i * j] += mu[i] * mu[j];
        }
    }
}
int main()
{
    init();
    for(scanf("%d", &t); t--;){
        scanf("%d%d", &n, &m);
        ans = 0;
        for(int T = 1; T <= min(n, m); T++){
            if(f[T]){
                long long g1 = 0, g2 = 0;
                for(int i = 1; i * T <= n; i++) g1 += mu[i * T];
                for(int i = 1; i * T <= m; i++) g2 += mu[i * T];
                ans += f[T] * g1 * g2;
            }
        }
        printf("%lld\n", ans);
    }
    return 0;
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!