luogu2257 YY的GCD

题目链接

problem

给出一个\(n,m(n,m\le 10^7)\),求\(\sum\limits_{i=1}^n\sum\limits_{j=1}^mgcd(i,j)\in P\)
P表示全部素数的集合。
\(T,(T\le 10000)\)组询问

solution

枚举因数
原式=\[\sum\limits_{d\in P} \sum\limits_{i=1}^{\frac{n}{d}}\sum\limits_{j=1}^{\frac{m}{d}}\epsilon(gcd(i,j)=1)\]
因为\(\epsilon=1*\mu\)
所以上式=\[\sum\limits_{d\in P} \sum\limits_{i=1}^{\frac{n}{d}}\sum\limits_{j=1}^{\frac{m}{d}}\sum\limits_{k|i,k|j}\mu(k)\\ =\sum\limits_{d\in P}\sum\limits_{k=1}^{\frac{min(n,m)}{d}}\mu(k)\lfloor\frac{n}{dk}\rfloor\lfloor\frac{m}{dk}\rfloor\]

\(t=dk\)

原式=\[\sum\limits_{t=1}^{min(n,m)}\lfloor\frac{n}{t}\rfloor \lfloor\frac{m}{t}\rfloor\sum\limits_{d\in P,d|t}\mu(\frac{t}{d})\]

发现前面这一块数论分块就好了,后面就提前预处理出来,求个前缀和。

预处理复杂度\(O(nloglogn)\),单次询问复杂度\(O(\sqrt{n})\)

code

    /*
    * @Author: wxyww
    * @Date:   2020-01-20 19:08:26
    * @Last Modified time: 2020-01-20 19:18:39
    */
    #include<cstdio>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #include<vector>
    #include<ctime>
    using namespace std;
    typedef long long ll;
    const int N = 10000010;
    ll read() {
        ll x=0,f=1;char c=getchar();
        while(c<'0'||c>'9') {
            if(c=='-') f=-1;
            c=getchar();
        }
        while(c>='0'&&c<='9') {
            x=x*10+c-'0';
            c=getchar();
        }
        return x*f;
    }
    int mu[N],pri[N],tot,vis[N];
    void pre() {
        mu[1] = 1;
        for(int i = 2;i < N;++i) {
            if(!vis[i]) pri[++tot] = i,mu[i] = -1;
            for(int j = 1;j <= tot && 1ll * i * pri[j] < N;++j) {
                vis[i * pri[j]] = 1;
                if(i % pri[j]) mu[i * pri[j]] = -mu[i];
                else {
                    mu[i * pri[j]] = 0;break;
                }
            }
        }
    }
    int f[N];
    int main() {
        pre();

        for(int i = 1;i <= tot;++i) {
            int js = 1;
            for(int k = pri[i];k < N;k += pri[i],++js) {
                f[k] += mu[js];
            }
        }

        for(int i = 1;i < N;++i) f[i] += f[i - 1];

        int T = read();
        while(T--) {
            int n = read(),m = read();
            ll ans = 0;
            for(int l = 1,r;l <= min(n,m);l = r + 1) {
                r = min(n / (n / l),m / (m / l));
                ans += 1ll * (n / l) * (m / l) * (f[r] - f[l - 1]);
            }
            printf("%lld\n",ans);
        }
        return 0;
    }

猜你喜欢

转载自www.cnblogs.com/wxyww/p/luogu2257.html