• 洛谷P2257 YY的GCD(莫比乌斯反演)


    传送门

    原来……莫比乌斯反演是这么用的啊……(虽然仍然不是很明白)

    首先,题目所求如下$$sum_{i=1}^nsum_{j=1}^m[gcd(i,j)=prim]$$

    我们设$f(d)$表示$gcd(i,j)=d$的$(i,j)$的对数,$g(d)$表示存在公因数为$d$的$(i,j)$的对数

    那么就有$$f(d)=sum_{i=1}^nsum_{j=1}^m[gcd(i,j)=d]$$

    $$g(d)=sum_{d|k}f(k)=lfloorfrac{N}{d} floorlfloorfrac{M}{d} floor$$

    那么根据莫比乌斯反演定理,则有$$f(n)=sum_{nmid d}mu(frac{d}{n})g(d)$$

    然后就可以化简了$$ans=sum_{pin prim}sum_{i=1}^nsum_{j=1}^m[gcd(i,j)=p]$$

    将$f(p)$代入,得$$ans=sum_{pin prim}f(p)$$

    $$ans=sum_{pin prim}sum_{pmid d}mu(frac{d}{p})g(d)$$

    我们考虑换一个枚举项,不枚举$p$,枚举$frac{d}{p}$

    $$ans=sum_{pin prim}sum_{d=1}^{min(lfloorfrac{n}{p} floor,lfloorfrac{m}{p} floor)}mu(d)g(dp)\=sum_{pin prim}sum_{d=1}^{min(lfloorfrac{n}{p} floor,lfloorfrac{m}{p} floor)}mu(d)lfloorfrac{n}{dp} floorlfloorfrac{m}{dp} floor$$

    然后我们把$dp$给换成$T$

    $$ans=sum_{T=1}^{min(n,m)}sum_{t|T,tin prim}mu(lfloorfrac{T}{t} floor)lfloorfrac{n}{T} floorlfloorfrac{m}{T} floor$$

    $$ans=sum_{T=1}^{min(n,m)}lfloorfrac{n}{T} floorlfloorfrac{m}{T} floor(sum_{t|T,tin prim}mu(lfloorfrac{T}{t} floor))$$

    然后对$(sum_{tmid T,tin prim}mu(frac{T}{t}))$求一个前缀和,就好了

    这数学公式真的是打的我心力憔悴……

     1 //minamoto
     2 #include<cstdio>
     3 #define ll long long
     4 //#define min(a,b) ((a)<(b)?(a):(b))
     5 inline int min(int a,int b){return a<b?a:b;}
     6 const int N=1e7+5;
     7 int vis[N],mu[N],p[N],g[N],m;ll sum[N],ans;
     8 void init(int n){
     9     mu[1]=1;
    10     for(int i=2;i<=n;++i){
    11         if(!vis[i]) p[++m]=i,mu[i]=-1;
    12         for(int j=1;j<=m&&p[j]*i<=n;++j){
    13             vis[i*p[j]]=1;
    14             if(i%p[j]==0) break;
    15             mu[i*p[j]]=-mu[i];
    16         }
    17     }
    18     for(int j=1;j<=m;++j)
    19     for(int i=1;i*p[j]<=n;++i)
    20     g[i*p[j]]+=mu[i];
    21     for(int i=1;i<=n;++i)
    22     sum[i]=sum[i-1]+g[i];
    23 }
    24 int main(){
    25 //    freopen("testdata.in","r",stdin);
    26     init(1e7);
    27     int T;scanf("%d",&T);
    28     while(T--){
    29         int n,m;
    30         scanf("%d%d",&n,&m);
    31         if(n>m) n^=m^=n^=m;
    32         ans=0;
    33         for(int l=1,r;l<=n;l=r+1){
    34             r=min(n/(n/l),m/(m/l));
    35             ans+=1ll*(n/l)*(m/l)*(sum[r]-sum[l-1]);
    36         }
    37         printf("%lld
    ",ans);
    38     }
    39     return 0;
    40 }
  • 相关阅读:
    UART中RTS、CTS
    Verdi:内存不足
    SV学习之interface
    perl学习之:@_ $_
    perl学习之:package and module
    代码变成可执行程序期间,编译器做了那些事?
    perl学习之:use & require
    perl学习之:use and require
    8位二进制补码表示整数的最小值是什么,最大值是什么
    深入理解计算机系统
  • 原文地址:https://www.cnblogs.com/bztMinamoto/p/9688510.html
Copyright © 2020-2023  润新知