• 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的值。

      ∑∑lcm(i,j) ,i=1..n,j=1..m

    =∑∑i*j/gcd(i,j) ,i=1..n,j=1..m

    =∑∑∑[gcd(i,j)=d]*i*j/d ,d=1..n,i=1..n,j=1..m (枚举gcd的取值d)

    =∑d*(∑∑[gcd(i,j)=1]*i*j) ,d=1..n,i=1..n/d,j=1..m/d

    =∑d*(∑a*a*mu[a]*( ∑∑i*j )) ,d=1..n,a=1..n/d,i=1..n/d/a,j=1..m/d/a  (由[n=1]=∑mu[d] ,d|n可得)

    a的取值只有O(n0.5)个,可以对每个取值只进行一次计算

    对每个a,(n/d/a,m/d/a)的取值也是O(n0.5)个,可以用同样方式优化

    ∑∑i*j用等差数列求和公式可以O(1)计算

    #include<cstdio>
    typedef long long i64;
    const int N=1e7,P=20101009;
    int ps[N/5],pp=0,mu[N+5];
    i64 m2[N+5];
    bool isnp[N+5];
    int n,m;
    inline i64 f(i64 a,i64 b){
        return ((a*(a+1)>>1)%P*((b*(b+1)>>1)%P))%P;
    }
    inline int min(int a,int b){
        return a<b?a:b;
    }
    int main(){
        scanf("%d%d",&n,&m);
        if(n>m)n^=m,m^=n,n^=m;
        mu[1]=1;
        for(int i=2;i<=n;i++){
            if(!isnp[i])ps[pp++]=i,mu[i]=-1;
            for(int j=0,k;j<pp&&(k=i*ps[j])<=n;j++){
                isnp[k]=1;
                if(i%ps[j])mu[k]=-mu[i];
                else break;
            }
        }
        for(int i=1;i<=n;i++){
            m2[i]=(mu[i]*1ll*i*i+m2[i-1])%P;
            if(m2[i]<0)m2[i]+=P;
        }
        i64 ans=0;
        for(int d=1,d2;d<=n;d=d2+1){
            d2=min(n/(n/d),m/(m/d));
            int x=n/d,y=m/d;
            i64 s=0;
            for(int a=1,b;a<=x;a=b+1){
                b=min(x/(x/a),y/(y/a));
                s+=(m2[b]-m2[a-1])*f(x/a,y/a)%P;
            }
            s%=P;
            ans=(ans+(1ll*(d+d2)*(d2-d+1)>>1)%P*s%P)%P;
        }
        if(ans<0)ans+=P;
        printf("%lld
    ",ans);
        return 0;
    }
  • 相关阅读:
    Emacs 使用YASnippet
    odbc备忘
    Emacs 矩形编辑
    ftp by libcurl
    emacsshell
    Emacs cnblogs 代码着色
    Emacs下的Man
    #include ""还是<>
    三种*
    应对Maze勒索攻击的最佳实践分享
  • 原文地址:https://www.cnblogs.com/ccz181078/p/5514680.html
Copyright © 2020-2023  润新知