zoukankan      html  css  js  c++  java
  • 【Luogu】P3327约数个数和(莫比乌斯反演+神奇数论公式)

      题目链接

      真TM是神奇数论公式。

      注明:如无特殊说明我们的除法都是整数除法,向下取整的那种。

      首先有个定理叫$d(ij)=sumlimits_{i|n}{}sumlimits_{j|m}{}(gcd(i,j)==1)$

      证明……我不会证qwq,可以看这个链接

      所以原式$sumlimits_{i=1}{n}sumlimits_{j=1}{m}d(ij)$

          =$sumlimits_{i=1}^{n}sumlimits_{j=1}^{m}sumlimits_{k=1}^{i}sumlimits_{l=1}^{j}[gcd(k,l)==1]$

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

      等等这个等号是怎么推过来的?题解一笔带过,然而我死活没看懂,于是请教rqy……

      以下是rqy的解析。

      $sumlimits_{i=1}^{n}sumlimits_{j=1}^{m}sumlimits_{k=1}^{i}sumlimits_{l=1}^{j}[gcd(k,l)==1]$

      =$sumlimits_{a=1}^{n}sumlimits_{b=1}^{m}[gcd(a,b)==1]sumlimits_{a|i}^{1<=i<=n}      sumlimits_{b|j}^{1<=j<=m}1$

      =$sumlimits_{a=1}^{n}sumlimits_{b=1}^{m}[gcd(a,b)==1]frac{n}{a}frac{m}{b}$

      然后把a统统替换成i,把b统统替换成j

      就证明完毕啦

      然后我们有了这个东西有什么用呢?

      emm公式打不出来了……看Night_Aurora的题解……

      

    那么可发现

    所以下文对于FS函数若第三项省略则表示第三项为1

    根据莫比乌斯反演

    那么

    那么答案就是F(N,M)了

    最后只差O(1)处理S函数了

    我们再设

    我们发现S(n,m)=V(n)*V(m)

    那么我们只要开始用O(N)打一个μ的前缀和

    再用O(N^1.5)试除法求出前50000个V函数的表

    再对每组询问进行试除法

    总复杂度是

      贴上我的代码

      

    #include<cstdio>
    #include<cstring>
    #include<cctype>
    #include<algorithm>
    #include<cstdlib>
    #define maxn 50060
    using namespace std;
    
    inline long long read(){
        long long num=0,f=1;
        char ch=getchar();
        while(!isdigit(ch)){
            if(ch=='-')    f=-1;
            ch=getchar();
        }
        while(isdigit(ch)){
            num=num*10+ch-'0';
            ch=getchar();
        }
        return num*f;
    }
    
    bool s[maxn];
    int prime[maxn],tot;
    int miu[maxn];
    long long v[maxn];
    
    int main(){
        miu[1]=1;
        for(int i=2;i<=maxn;++i){
            if(!s[i]){
                prime[++tot]=i;
                miu[i]=-1;
            }
            for(int j=1;j<=tot&&prime[j]*i<=maxn;++j){
                s[i*prime[j]]=1;
                if(!(i%prime[j]))    break;
                miu[i*prime[j]]=-miu[i];
            }
        }
        for(int i=1;i<=maxn;++i)    miu[i]+=miu[i-1];
        for(int n=1;n<=maxn;++n){
            int x=1;
            while(x<=n){
                int y=n/(n/x);
                v[n]+=(y-x+1)*(n/x);
                x=y+1;
            }
        }
        int T=read();
        while(T--){
            int n=read(),m=read();    long long ans=0;
            int x=1,top=min(n,m);
            while(x<=top){
                int y=min(n/(n/x),m/(m/x));
                ans+=(long long)(v[n/y]*(long long)v[m/y])*(long long)(miu[y]-miu[x-1]);
                x=y+1;
            }
            printf("%lld
    ",ans);
        }
        return 0;
    }

      这篇博客……勉勉强强算是写(抄)完了吧……

  • 相关阅读:
    好用的软件记录
    微信小程序 设计理念指南
    开启Python之路
    升级到iOS9之后的相关适配
    ARC模式下的内存泄露问题
    Git 源代码管理工具
    SVN版本控制系统
    单例 singleton
    双击改变图片大小和多点触摸改变图片大小
    循环引用 -- id 为什么是 assign 而不是 retain
  • 原文地址:https://www.cnblogs.com/cellular-automaton/p/8206752.html
Copyright © 2011-2022 走看看