zoukankan      html  css  js  c++  java
  • bzoj2154 Crash的数字表格 莫比乌斯反演

    Description

    今天的数学课上,Crash小朋友学习了最小公倍数(Least Common Multiple)。对于两个正整数a和b,LCM(a, b)表示能同时被a和b整除的最小正整数。例如,LCM(6, 8) = 24。回到家后,Crash还在想着课上学的东西,为了研究最小公倍数,他画了一张N*M的表格。每个格子里写了一个数字,其中第i行第j列的那个格子里写着数为LCM(i, j)。一个4*5的表格如下: 1 2 3 4 5 2 2 6 4 10 3 6 3 12 15 4 4 12 4 20 看着这个表格,Crash想到了很多可以思考的问题。不过他最想解决的问题却是一个十分简单的问题:这个表格中所有数的和是多少。当N和M很大时,Crash就束手无策了,因此他找到了聪明的你用程序帮他解决这个问题。由于最终结果可能会很大,Crash只想知道表格里所有数的和mod 20101009的值。

    Input

    输入的第一行包含两个正整数,分别表示N和M。

    Output

    输出一个正整数,表示表格中所有数的和mod 20101009的值。

    Sample Input

    4 5

    Sample Output

    122
    【数据规模和约定】
    100%的数据满足N, M ≤ 107。
     
    http://blog.csdn.net/outer_form/article/details/50593188
     
     1 #include<cstring>
     2 #include<cmath>
     3 #include<iostream>
     4 #include<algorithm>
     5 #include<cstdio>
     6 
     7 #define ll long long
     8 #define N 10000007
     9 #define mod 20101009
    10 using namespace std;
    11 inline int read()
    12 {
    13     int x=0,f=1;char ch=getchar();
    14     while(ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
    15     while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    16     return x*f;
    17 }
    18 
    19 ll n,m,ans;
    20 ll sm[N];
    21 int tot,mu[N],pri[N];
    22 bool flag[N];
    23 
    24 ll sum(ll x,ll y)
    25 {
    26     return ((x*(x+1)/2)%mod)*((y*(y+1)/2)%mod)%mod;
    27 }
    28 void init_mu()
    29 {
    30     mu[1]=1;
    31     for (int i=2;i<=min(n,m);i++)
    32     {
    33         if (!flag[i])pri[++tot]=i,mu[i]=-1;
    34         for (int j=1;j<=tot&&(ll)pri[j]*i<=min(n,m);j++)
    35         {
    36             flag[pri[j]*i]=1,mu[pri[j]*i]=-mu[i];
    37             if (i%pri[j]==0){mu[pri[j]*i]=0;break;}
    38         }
    39     }
    40     for (ll i=1;i<=min(n,m);i++)
    41         sm[i]=(sm[i-1]+(i*i*mu[i])%mod)%mod;
    42 }
    43 ll F(ll x,ll y)
    44 {
    45     ll ans=0,ps;
    46     for (ll i=1;i<=min(x,y);i=ps+1)
    47     {
    48         ps=min(x/(x/i),y/(y/i));
    49         ans=(ans+(sm[ps]-sm[i-1])%mod*sum(x/i,y/i)%mod)%mod;
    50     }
    51     return ans;
    52 }
    53 int main()
    54 {
    55     n=read(),m=read();
    56     init_mu();
    57     ll ps=0;
    58     for (ll i=1;i<=min(n,m);i=ps+1)
    59     {
    60         ps=min(n/(n/i),m/(m/i));
    61         ans=(ans+(i+ps)*(ps-i+1)/2%mod*F(n/i,m/i)%mod)%mod;
    62     }
    63     ans=(ans%mod+mod)%mod;
    64     printf("%lld
    ",ans);
    65 }

    题目大意就是求ni=1mj=1lcm(i,j)
    分析:

    ans=i=1nj=1mlcm(i,j)=i=1nj=1mijgcd(i,j)


    枚举d=gcd(i,j),

    f(n,m,k)=1<=i<=n1<=j<=mgcd(i,j)=kij


    显然可以得到 

    ans=d=1min(n,,m)d2f(nd,md,1)d=d=1min(n,,m)df(nd,md,1)


    即算出除以d后互质的对数,两个数都乘d的乘积就得到了两个数的乘积,在除以d就是他们的最小公倍数。 
    那怎么求f呢 

    sum(x,y)=1<=i<=x1<=j<=yij=x(x+1)2y(y+1)2
    F(x,y,k)=1<=i<=x1<=j<=yk|gcd(i,j)ij=k2sum(nkmk)=k|df(i,j,d)
    f(x,y,k)=k|dμ(dk)F(x,y,d)


    所以

    f(x,y,1)=k=1min(m,n)μ(k)F(x,y,k)=k=1min(x,y)μ(k)k2sum(xkyk)=k=1min(x,y)μ(k)k2xk(xk+1)2yk(yk+1)2
  • 相关阅读:
    git分支操作
    redis 和 memcached 有什么区别?redis 的线程模型是什么?为什么 redis 单线程却能支撑高并发?
    缓存如果使用不当会造成什么后果?
    在项目中缓存是如何使用的?
    excel poi3.17导出导入
    Mongodb: Sort operation used more than the maximum 33554432 bytes of RAM
    VMware12上安装CentOS7
    校验文件是否是Excel文件
    读后感——《构建之法》第1.2.3章
    操作系统——实验一
  • 原文地址:https://www.cnblogs.com/fengzhiyuan/p/8185092.html
Copyright © 2011-2022 走看看