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

      ∑∑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;
    }
  • 相关阅读:
    Longest Palindromic Substring
    PayPal MLSE job description
    Continuous Median
    Remove Duplicates From Linked List
    Valid IP Address
    Longest substring without duplication
    Largest range
    Subarray sort
    Multi String Search
    Suffix Trie Construction
  • 原文地址:https://www.cnblogs.com/ccz181078/p/5514680.html
Copyright © 2011-2022 走看看