zoukankan      html  css  js  c++  java
  • [BZOJ2301][HAOI2011]Problem B

    题目大意

    对于给出的 (n) 次询问,每次给定 (a,b,c,d,k) 五个数,询问 (displaystyle sum_{x=a}^bsum_{y=c}^dig[(x,y)=kig]) 的值。数据保证 (nleqslant 50000,1leqslant aleqslant bleqslant 50000,1leqslant cleqslant dleqslant 50000)

    解析

    首先利用容斥原理将一个询问拆分成四个,每次求 (displaystyle sum_{x=1}^nsum_{y=1}^mig[(x,y)=kig]) 的值。考虑莫比乌斯反演,设 (F(k))(k|(x,y)) 的对数,(f(k))((x,y)=k) 的个数,则有以下关系:

    [F(k)=sum_{x=1}^{iglfloorfrac{n}{k}ig floor}f(kcdot x) ]

    只需快速求出 (F(k))。若 (k|x,k|y),则 (x=kcdot t_1,y=kcdot t_2),只需统计有多少对 ((t_1,t_2))。得:

    [displaystyle F(k)=Biglfloorfrac{n}{k}Big floorBiglfloorfrac{m}{k}Big floor ]

    由莫比乌斯反演可求得 (f(k))

    [f(k)=sum_{x=1}^{iglfloorfrac{n}{k}ig floor}igg(mu(x)cdot F(kcdot x)igg)=sum_{x=1}^{iglfloorfrac{n}{k}ig floor}igg(mu(x)Biglfloorfrac{n}{kx}Big floorBiglfloorfrac{m}{kx}Big floorigg) ]

    暴力求 (f(k))(O(n)),注意到 (displaystyle Biglfloorfrac{n}{d}Big floor) 有至多 (O(sqrt{n})) 个取值,所以可以考虑使用数论分块求解

    证明:

    • 当 $1leqslant d < sqrt{n}$ 时,由于 $d$ 只有 $sqrt{n}$ 个,所以 $displaystyle Biglfloorfrac{n}{d}Big floor$ 也至多有 $sqrt{n}$ 个取值。
    • 当 $sqrt{n}leqslant dleqslant n$ 时,由于 $displaystyle Biglfloorfrac{n}{d}Big floor$ 只有 $sqrt{n}$ 个,所以 $displaystyle Biglfloorfrac{n}{d}Big floor$ 也只有至多 $sqrt{n}$ 个取值。
    • 故 $displaystyle Biglfloorfrac{n}{d}Big floor$ 至多有 $O(sqrt{n})$ 个取值。

    同理 (displaystyle Biglfloorfrac{m}{d}Big floor) 也只有至多 (O(sqrt{m})) 个取值,所以 (displaystyle Biglfloorfrac{n}{kx}Big floor)(displaystyle Biglfloorfrac{m}{kx}Big floor) 都不变的段数有 (O(sqrt{n}+sqrt{m})) 段。对于相等的段,求出 (mu) 函数的前缀和,即可批量计算这一个段的答案。

    #include <bits/stdc++.h>
    using namespace std;
    
    const int maxn = 50010;
    int T, tot, prime[maxn], mu[maxn], sum[maxn];
    
    void sieve() {
        fill(prime, prime + maxn, 1);
        mu[1] = 1, tot = 0;
        for (int i = 2; i < maxn; i++) {
            if (prime[i]) {
                prime[++tot] = i, mu[i] = -1;
            }
            for (int j = 1; j <= tot && i * prime[j] < maxn; j++) {
                prime[i * prime[j]] = 0;
                if (i % prime[j] == 0) {
                    mu[i * prime[j]] = 0;
                    break;
                } else {
                    mu[i * prime[j]] = -mu[i];
                }
            }
        }
        for (int i = 1; i < maxn; i++) {
            sum[i] = sum[i - 1] + mu[i];
        }
    }
    
    int calc(int n, int m, int k) {
        if (n > m) swap(n, m);
        int ans = 0;
        n /= k, m /= k;
        for (int i = 1, nxt = 1; i <= n; i = nxt + 1) {
            nxt = min(n / (n / i), m / (m / i));
            ans += (sum[nxt] - sum[i - 1]) * (n / i) * (m / i);
        }
        return ans;
    }
    
    int main() {
        sieve();
        scanf("%d", &T);
        while (T--) {
            int a, b, c, d, k;
            scanf("%d %d %d %d %d", &a, &b, &c, &d, &k);
            printf("%d
    ", calc(b, d, k) - calc(b, c - 1, k) - calc(a - 1, d, k) + calc(a - 1, c - 1, k));
        }
        return 0;
    }
    
  • 相关阅读:
    作为一个程序猿,是不是经常会用到.chm文档,但是我们可能会遇到这样那样的问题,比如.chm文档打不开
    总结
    图片轮播的几种方式
    学习中于遇到的问题总结
    node 总结
    webpack 总结
    babel 的总结和理解
    关于css 的AST 语法树的理解
    js中的正则表达式
    八皇后
  • 原文地址:https://www.cnblogs.com/Alessandro/p/9748645.html
Copyright © 2011-2022 走看看