zoukankan      html  css  js  c++  java
  • [bzoj3994] [SDOI2015] 约数个数和

    Description

    (d(x))(x) 的约数个数,给定 (N)(M),求 (sumlimits_{i=1}^N sumlimits_{j=1}^M d(ij))

    Input

    输入文件包含多组测试数据。
    第一行,一个整数 (T) ,表示测试数据的组数。
    接下来的 (T) 行,每行两个整数 (N)(M)

    Output

    (T) 行,每行一个整数,表示你所求的答案。

    Sample Input

    2

    7 4

    5 6

    Sample Output

    110

    121

    HINT

    (1<=N, M<=50000)
    (1<=T<=50000)


    想法

    首先有一个结论
    $ d(i,j)=sumlimits_{x|i} sumlimits_{y|j} [gcd(x,y)==1] $
    原谅我不会证 (qwq)

    接下来,喜闻乐见的推式子

    [egin{equation*} egin{aligned} &sumlimits_{i=1}^n sumlimits_{j=1}^m d(ij) \ =&sumlimits_{i=1}^n sumlimits_{j=1}^m sumlimits_{x|i} sumlimits_{y|j} [gcd(x,y)==1] \ =&sumlimits_{i=1}^n sumlimits_{j=1}^m [gcd(x,y)==1] imes lfloor frac{n}{x} floor imes lfloor frac{m}{y} floor \ end{aligned} end{equation*} ]

    (f(i)=sumlimits_{i=1}^n sumlimits_{j=1}^m [gcd(x,y)==1] imes lfloor frac{n}{x} floor imes lfloor frac{m}{y} floor)
    应用莫比乌斯反演

    [egin{equation*} egin{aligned} F(i)&=f(i)+f(2i)+... \ &=sumlimits_{x=1}^{lfloor frac{n}{i} floor} sumlimits_{y=1}^{lfloor frac{m}{i} floor} lfloor frac{n}{ix} floor lfloor frac{m}{iy} floor \ &=sumlimits_{x=1}^{lfloor frac{n}{i} floor} lfloor frac{n}{ix} floor sumlimits_{y=1}^{lfloor frac{m}{i} floor} lfloor frac{m}{iy} floor end{aligned} end{equation*} ]

    不妨设 (s(x)=sumlimits_{i=1}^x lfloor frac{x}{i} floor)
    它可以预处理后 (O(1)) 调用
    (f(i)=sumlimits_{i|d} mu(frac{d}{i}) s(frac{n}{d}) s(frac{m}{d}))
    那么

    [egin{equation*} egin{aligned} ans&=f(1) \ &=sumlimits_{i=1}^{min(n,m)} mu(i) s(frac{n}{i})s(frac{m}{i}) end{aligned} end{equation*} ]

    然后就好啦。


    代码

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
     
    using namespace std;
     
    const int N = 50005;
    typedef long long ll;
     
    ll s[N];
    int mu[N],p[N],prime[N],pnum,sum[N];
    void getp(){
        mu[1]=sum[1]=1;
        for(int i=2;i<N;i++) p[i]=1;
        for(int i=2;i<N;i++){
            if(p[i]) prime[pnum++]=i,mu[i]=-1;
            for(int j=0;j<pnum && (ll)prime[j]*i<N;j++){
                p[i*prime[j]]=0;
                if(i%prime[j]==0){
                    mu[i*prime[j]]=0;
                    break;
                }
                mu[i*prime[j]]=-mu[i];
            }
            sum[i]=sum[i-1]+mu[i];
        }
    }
    void gets(){
        for(int x=1;x<N;x++){
            for(int l=1,r;l<=x;l=r+1){
                r=x/(x/l);
                s[x]+=1ll*(x/l)*(r-l+1);
            }
        }
    }
     
    int main()
    {
        int T,n,m;
        getp(); gets();
         
        scanf("%d",&T);
        while(T--){
            scanf("%d%d",&n,&m);
            ll ans=0;
            for(int l=1,r;l<=n && l<=m;l=r+1){
                r=min(n/(n/l),m/(m/l));
                ans+=s[n/l]*s[m/l]*(sum[r]-sum[l-1]);
            }
            printf("%lld
    ",ans);
        }
         
        return 0;
    }
    
    
    既然选择了远方,便只顾风雨兼程
  • 相关阅读:
    JVM 内存布局
    线程池总结
    Redis持久化
    Java编程基础
    toString()、String.valueOf、(String)强转
    4 种主流的 API 架构风格对比
    kubernetes 节点设置不可调度
    Linux下如何查看哪些进程占用的CPU内存资源最多
    Linux openssl1.0.2k升级openssl1.1.1e版本教程
    对一些权限题密码的说明
  • 原文地址:https://www.cnblogs.com/lindalee/p/10539858.html
Copyright © 2011-2022 走看看