标签: 莫比乌斯反演

[POI2007]ZAP-Queries 题解

[POI2007]ZAP-Queries 题解

题目地址:洛谷:【P3455】[POI2007]ZAP-Queries – 洛谷、BZOJ:Problem 1101. — [POI2007]Zap

题目描述

FGD正在破解一段密码,他需要回答很多类似的问题:对于给定的整数a,b和d,有多少正整数对x,y,满足x<=a,y<=b,并且gcd(x,y)=d。作为FGD的同学,FGD希望得到你的帮助。

输入输出格式

输入格式:
第一行包含一个正整数n,表示一共有n组询问。(1<=n<= 50000)接下来n行,每行表示一个询问,每行三个
正整数,分别为a,b,d。(1<=d<=a,b<=50000)

输出格式:
对于每组询问,输出到输出文件zap.out一个正整数,表示满足条件的整数对数。

输入输出样例

输入样例#1:

2
4 5 2
6 4 3

输出样例#1:

3
2

说明

对于第一组询问,满足条件的整数对有(2,2),(2,4),(4,2)。对于第二组询问,满足条件的整数对有(
6,3),(3,3)。

题解

这个题[HDU1695]GCD的一个强化版,把方法搬上来套一个整除分块就好。
总复杂度O(n \sqrt{n})

代码

// Code by KSkun, 2018/6
#include <cstdio>
#include <cctype>  

#include <algorithm>

typedef long long LL;

inline char fgc() {
    static char buf[100000], *p1 = buf, *p2 = buf;
    return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) 
        ? EOF : *p1++;
}

inline LL readint() {
    register LL res = 0, neg = 1;
    register char c = fgc();
    while(!isdigit(c)) {
        if(c == '-') neg = -1;
        c = fgc();
    }
    while(isdigit(c)) {
        res = (res << 1) + (res << 3) + c - '0';
        c = fgc();
    }
    return res * neg;
}

const int MAXN = 50005;

bool notprime[MAXN];
int prime[MAXN], miu[MAXN], ptot;

inline void sieve() {
    miu[1] = 1;
    for(int i = 2; i < MAXN; i++) {
        if(!notprime[i]) {
            prime[ptot++] = i;
            miu[i] = -1;
        }
        for(int j = 0; j < ptot && prime[j] * i < MAXN; j++) {
            int k = prime[j] * i;
            notprime[k] = true;
            if(i % prime[j] == 0) {
                miu[k] = 0; break;
            } else {
                miu[k] = -miu[i];
            }
        }
    }
    for(int i = 2; i < MAXN; i++) {
        miu[i] += miu[i - 1];
    }
}

int T, b, d, k;

int main() {
    sieve();
    T = readint();
    while(T--) {
        LL all = 0, rep = 0;
        b = readint(); d = readint(); k = readint();
        if(!k) {
            printf("0\n");
            continue;
        }
        b /= k; d /= k;
        if(b > d) std::swap(b, d);
        for(int i = 1; i <= b;) {
            int j = std::min(b / (b / i), d / (d / i));
            all += 1ll * (miu[j] - miu[i - 1]) * (b / i) * (d / i);
            i = j + 1;
        }
        printf("%lld\n", all);
    }
    return 0;
}
反演(莫比乌斯反演、二项式反演)原理及应用

反演(莫比乌斯反演、二项式反演)原理及应用

莫比乌斯函数(Möbius function)

定义

莫比乌斯函数\mu(n)定义为:
\mu(n) = \begin{cases} 1 & (n=1) \\ (-1)^k & (n = p_1p_2 \cdots p_k) \\ 0 & (p^k|n, k > 1) \end{cases}
文字描述是这样的。定义\mu(1)=1;如果n是k个互异的质因数的乘积,则\mu(n)=(-1)^k;如果n中含有一个质因数的次数超过1,则\mu(n)=0
这是一个积性函数。

性质

  1. \sum_{d|n} \mu(d) = \begin{cases} 1 & (n=1) \\ 0 & (n \neq 1) \end{cases}
  2. \sum_{d|n} \frac{\mu(d)}{d} = \frac{\varphi(n)}{n}

狄利克雷卷积(Dirichlet convolution)

定义

对于数论函数f(n)和g(n),定义其狄利克雷卷积为
(f * g)(n) = \sum_{d|n} f(d)g(\frac{n}{d})

性质

  • 交换律:f * g = g * f
  • 结合律:f * (g * h) = (f * g) * h
  • 对加法的分配律:f * (g + h) = f * g + f * h
  • 积性函数的点积和狄利克雷卷积也是积性函数

莫比乌斯反演(Möbius inversion)

假设数论函数f(n)与F(n)满足:F(n) = \sum_{d|n} f(d),则
f(n) = \sum_{d|n} \mu(d) F(\frac{n}{d})
另外一种形式:
假设数论函数f(n)与F(n)满足:F(n) = \sum_{n|d} f(d),则
f(n) = \sum_{n|d} \mu(\frac{d}{n}) F(d)

二项式反演

f(n) = \sum_{i=0}^n \mathrm{C}_n^i g(i) \Rightarrow g(n) = \sum_{i=0}^n (-1)^{n-i} \mathrm{C}_n^i f(i)

参考资料