zoukankan      html  css  js  c++  java
  • bzoj2820

    bzoj2820 - YY的GCD (莫比乌斯函数,筛法,数论分块)

    题目

    给定N, M,求1<=x<=N, 1<=y<=M且gcd(x, y)为质数的(x, y)有多少对(多组输入)

    题解

    前置题目:

    [sumlimits_p{sumlimits^n_{i=1}{sumlimits^m_{j=1}{[gcd(i,j)=p]}}} ]

    [sumlimits_p{sumlimits^{frac{n}{p}}_{i=1}{sumlimits^{frac{m}{p}}_{j=1}{sumlimits_{d|gcd(i,j)}{mu(d)}}}} ]

    [sumlimits_p{sumlimits_{d}{mu(d)sumlimits^{frac{n}{p}}_{i=1}{[d|i]sumlimits^{frac{m}{p}}_{j=1}{[d|j]}}}} ]

    [sumlimits_p{sumlimits_{d}{mu(d) lfloorfrac{n}{pd} floorlfloorfrac{m}{pd} floor}} ]

    (T=pd)

    [sumlimits^{min(n, m)}_{T=1}{sumlimits_{p|T}{mu(frac{T}{p}) lfloorfrac{n}{T} floorlfloorfrac{m}{T} floor}} ]

    (f(T)=sumlimits_{p|T}{mu(frac{T}{p})}),它可以用埃式筛筛出来。然后求得(f(T)),接下来就是简单的数论分块了。细节详见代码。

    #include <bits/stdc++.h>
    
    #define endl '
    '
    #define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
    #define mp make_pair
    #define seteps(N) fixed << setprecision(N) 
    typedef long long ll;
    
    using namespace std;
    /*-----------------------------------------------------------------*/
    
    ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
    #define INF 0x3f3f3f3f
    
    const int N = 1e7 + 10;
    const double eps = 1e-5;
    
    ll f[N];
    int mu[N];
    int cnt;
    int prime[N];
    bool isnp[N];
    ll pre[N];
    
    void init() {
        mu[1] = 1;
        f[1] = 0;
        for(int i = 2; i < N; i++) {
            if(!isnp[i]) {
                mu[i] = -1;
                prime[cnt++] = i;
            }
            for(int j = 0; j < cnt; j++) {
                int p = prime[j];
                if(i * p >= N) break;
                isnp[i * p] = 1;
                if(i % p == 0) {
                    mu[i * p] = 0;
                    break;
                }
                mu[i * p] = -mu[i];
            }
        }
        
        for(int i = 2; i < N; i++) { //埃式筛筛f(T)
            if(!isnp[i]) {
                f[i] = 1;
                for(int j = 2 * i; j < N; j += i) {
                    f[j] += mu[j / i];
                }
            }
        }
        pre[0] = 0;
        for(int i = 1; i < N; i++) pre[i] += pre[i - 1] + f[i]; //前缀和
    }
    
    
    int main() {
        IOS;
        init();
        int t;
        cin >> t;
        while(t--) {
            int n, m;
            cin >> n >> m;
            ll ans = 0;
            int cur = 1;
            while(cur <= min(n, m)) { //数论分块
                int p1 = n / (n / cur);
                int p2 = m / (m / cur);
                int nt = min(min(n, m), min(p1, p2));
                ans += 1ll * (n / cur) * (m / cur) * 1ll * (pre[nt] - pre[cur - 1]);
                cur = nt + 1;
            }
            cout << ans << endl;
        }
    }
    
  • 相关阅读:
    C语言ll作业01
    C语言寒假大作战04
    C语言寒假大作战03
    C语言寒假大作战02
    C语言寒假大作战01
    C语言I作业12—学期总结
    C语言I博客作业11
    C语言I博客作业10
    第三章预习笔记-运算方法和运算部件
    非数值数据的编码表示
  • 原文地址:https://www.cnblogs.com/limil/p/14063321.html
Copyright © 2011-2022 走看看