[luogu3455][POI2007]ZAP-Queries

题目描述

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

分析

很明显的一道莫比乌斯反演,但是还没有写过学习笔记,之后一定补起来(flag)。

\[f(k)=\sum^a_{i=1}\sum^b_{j=1}[gcd(i,j)=k]\]
\[F(k) = \sum_{n|k}f(k)= \lfloor \frac{a}{n} \rfloor \lfloor \frac{b}{n} \rfloor \]
由反演退出以下的式子:
\[f(n) = \sum_{n|k} \mu (\lfloor \frac{k}{n}\rfloor) F(k)\]
那么答案就是\(f(d)\),
我们枚举整除分块$\lfloor \frac k d \rfloor $
递推式就是:
\[ans=\sum^{min(a,b)}_{t=1} \mu(t) \lfloor \frac{a}{td} \rfloor \lfloor \frac{b}{td} \rfloor \]
多组数据我们就用整除分块,差不多复杂度是\(O(t\sqrt{n})\)
ps.记得要开long long。

ac代码

#include <bits/stdc++.h>
#define ll long long
#define ms(a, b) memset(a, b, sizeof(a))
#define inf 0x3f3f3f3f
using namespace std;
template <typename T>
inline void read(T &x) {
    x = 0; T fl = 1;
    char ch = 0;
    while (ch < '0' || ch > '9') {
        if (ch == '-') fl = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9') {
        x = (x << 1) + (x << 3) + (ch ^ 48);
        ch = getchar();
    }
    x *= fl;
}
#define N 500005
ll sum[N], mui[N], prime[N];
int cnt;
bool vis[N];
void get_mui(ll MAXN) {
    mui[1] = 1;
    for (ll i = 2; i <= MAXN; i ++) {
        if (!vis[i]) {
            mui[i] = -1;
            prime[++ cnt] = i;
        }
        for (ll j = 1; j <= cnt && prime[j] * i <= MAXN; j ++) {
            vis[prime[j] * i] = 1;
            if (i % prime[j] == 0) break;
            else mui[prime[j] * i] = -mui[i];
        }
    }
    for (ll i = 1; i <= MAXN; i ++) sum[i] = sum[i - 1] + mui[i];
}
int main() {
    int cas; 
    read(cas);
    get_mui(500000);
    while (cas --) {
        ll a, b, d;
        read(a); read(b); read(d);
        ll ans = 0;
        for (ll l = 1, r; l <= min(a, b); l = r + 1) {
            r = min(a / (a / l), b / (b / l));
            ans += (a / (l * d) * (b / (l * d))) * (sum[r] - sum[l - 1]);
        }
        printf("%lld\n", ans);
    }
    return 0;
}
上一篇:(1)go web开发之 zap日志库的使用及gin框架配置zap记录日志详细文档讲解分析


下一篇:BZOJ 1108: [POI2007]天然气管道Gaz 性质分析_小结论_巧妙