• 洛谷


    https://www.luogu.org/problemnew/show/P2257

    (n,m)(gcd(i,j)==p) 的数对的个数

    求 $sumlimits_p sumlimits_{i=1}^{n}sumlimits_{j=1}^{m}[gcd(i,j)==p] $

    由套路:
    (=sumlimits_p sumlimits_{k=1}^{N}mu(k) lfloorfrac{n}{kp} floor lfloorfrac{m}{kp} floor)

    再套路:
    (=sumlimits_p sumlimits_{T=kp}^{N}mu(frac{T}{p}) lfloorfrac{n}{T} floor lfloorfrac{m}{T} floor)

    交换求和:
    (=sumlimits_{T=1}^{N} sumlimits_{p|T} mu(frac{T}{p}) lfloorfrac{n}{T} floor lfloorfrac{m}{T} floor)

    提T:
    (=sumlimits_{T=1}^{N} lfloorfrac{n}{T} floor lfloorfrac{m}{T} floor sumlimits_{p|T} mu(frac{T}{p}))

    后面的式子可以预处理,方法是在筛出质数表和莫比乌斯函数表之后,枚举每个质数p,再枚举倍数k,给kp加上 (mu(k)) .

    前面的式子可以整除分块 (r=min(n/(n/l),m/(m/l))) .

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define MAXN 10000000+5
    
    /* 莫比乌斯函数筛 begin */
    
    int mu[MAXN];
    int pri[MAXN],pritop;
    bool notpri[MAXN];
    //pritop从1开始计数
    
    int sumdmu[MAXN],prefixsumdmu[MAXN];
    
    void sieve3(int n) {
        notpri[1]=mu[1]=1;
        for(int i=2; i<=n; i++) {
            if(!notpri[i])
                pri[++pritop]=i,mu[i]=-1;
            for(int j=1; j<=pritop&&i*pri[j]<=n; j++) {
                notpri[i*pri[j]]=1;
                //略有不同
                if(i%pri[j])
                    mu[i*pri[j]]=-mu[i];
                else {
                    mu[i*pri[j]]=0;
                    break;
                }
            }
        }
    
        for(int j=1; j<=pritop; j++) {
            for(int i=1;i*pri[j]<=n;i++){
                sumdmu[i*pri[j]]+=mu[i];
            }
        }
        for(int i=1;i<=n;i++)
            prefixsumdmu[i]=prefixsumdmu[i-1]+sumdmu[i];
    }
    
    /* 莫比乌斯函数筛 end */
    
    
    //整除分块,n,m版
    ll aliquot_patition(int n,int m) {
        ll ans=0;
        int N=min(n,m);
        for(int l=1,r; l<=N; l=r+1) {
            r=min(n/(n/l),m/(m/l));
            ans+=1ll*(n/l)*(m/l)*(prefixsumdmu[r]-prefixsumdmu[l-1]);
        }
        return ans;
    }
    
    int main() {
        sieve3(10000000);
        int T;
        scanf("%d",&T);
        while(T--){
            int n,m;
            scanf("%d%d",&n,&m);
            printf("%lld
    ",aliquot_patition(n,m));
        }
    }
    
  • 相关阅读:
    自我介绍
    目前流行的源程序版本管理软件和项目管理软件的优缺点
    四月是你的谎言
    软件分析(Mobile Apps )--百词斩
    程序扩展
    超级无敌小学四则运算题目程序
    4组 团队展示
    2020面向对象设计与构造 第四单元 & 课程 博客总结
    2020面向对象设计与构造 第三单元 博客总结
    2020面向对象设计与构造 第二单元 博客总结
  • 原文地址:https://www.cnblogs.com/Yinku/p/10672617.html
Copyright © 2020-2023  润新知