Loading

HDU-4726 Mophues 莫比乌斯反演

HDU-4726 Mophues 莫比乌斯反演

题意

多个询问,求\([1,m],[1,n]\) 中有多少对数的\(GCD\) 的素因子个数小于\(p\)

\[n,m,p\leq 5\cdot 10^5 ,q\leq 5000 \]

分析

将题意用数学语言表示即求

\[\sum_{i=1}^n\sum_{j=1}^m[f(gcd(i,j)) < p] \]

其中\(f\) 函数表示质因子的个数(可重复)

下面进行化简

\[\sum_{i=1}^n\sum_{j=1}^m[f(gcd(i,j)) < p] \\ = \sum_{d = 1}^{min(n,m)}[f(d)<p]\sum_{i=1}^n\sum_{j=1}^m[gcd(i,j)=d] \\ =\sum_{d = 1}^{min(n,m)}[f(d)<p]\sum_{i=1}^{\frac{n}{d}}\sum_{j=1}^{\frac{m}{d}}[gcd(i,j)=1] \\ =\sum_{d = 1}^{min(n,m)}[f(d)<p]\sum_{i=1}^{\frac{n}{d}}\sum_{j=1}^{\frac{m}{d}}\epsilon (gcd(i,j)) \\ =\sum_{d = 1}^{min(n,m)}[f(d)<p]\sum_{i=1}^{\frac{n}{d}}\sum_{j=1}^{\frac{m}{d}}\sum_{r|gcd(i,j)}\mu(r) \\ =\sum_{d = 1}^{min(n,m)}[f(d)<p]\sum_{d|r}\mu(\frac{r}{d})\lfloor\frac{n}{r}\rfloor\lfloor\frac{m}{r}\rfloor \\ =\sum_{r=1}^{min(n,m)}\lfloor\frac{n}{r}\rfloor\lfloor\frac{m}{r}\rfloor \sum_{d|r}\mu(\frac{r}{d})[f(d)<p] \]

注意到前半部分可以整除分块,后半部分可以通过筛法筛出,再前缀和一下就好了

另外需要注意到的性质是由于\(n,m\) 范围比较小 \(p\) 只有在\(<20\) 时才需要计算,否则全当满足即可,输出\(nm\)

代码

int prime[maxn], prime_tot;
int is_prime[maxn];
int mu[maxn];
int num[maxn];
int dp[22][maxn];

void pre_calc(int lim) {
    mu[1] = 1;
    for (int i = 2; i <= lim; i++) {
        if (!is_prime[i]) {
            prime[++prime_tot] = i;
            mu[i] = -1;
            num[i] = 1;
        } 
        for (int j = 1; j <= prime_tot; j++) {
            if (i * prime[j] > lim) break;
            is_prime[i * prime[j]] = 1;
            num[i * prime[j]] = num[i] + 1;
            if (i % prime[j] == 0) {
                mu[i * prime[j]] = 0;
                break;
            }
            else mu[i * prime[j]] = -mu[i];
        }
    }
    for (int i = 1; i <= lim; i++)
        for (int j = i; j <= lim; j += i)
            dp[num[i]][j] += mu[j / i];
    for (int i = 1; i <= lim; i++)
        for (int j = 1; j < 20; j++)
            dp[j][i] += dp[j - 1][i];
    for (int i = 1; i <= lim; i++)
        for (int j = 0; j < 20; j++)
            dp[j][i] += dp[j][i - 1];
}

int main() {
    pre_calc(5e5 + 3);
    int T = readint();
    while (T--) {
        ll res = 0;
        ll n, m, p;
        n = readll(), m = readll(), p = readll();
        if (p >= 20) {
            Put(n * m);
            puts("");
            continue;
        }
        for (ll i = 1; i <= min(n, m); i) {
            ll l, r;
            l = i, r = min(n / (n / i), m / (m / i));
            res += (n / i) * (m / i) * (dp[p][r] - dp[p][l - 1]);
            i = r + 1;
        }
        Put(res);
        puts("");
    }
}
posted @ 2020-08-31 10:02  MQFLLY  阅读(156)  评论(0编辑  收藏  举报