洛谷 P1829 [国家集训队]Crash的数字表格 / JZPTAB

题目链接

先把式子写出来~

\(ans=\sum\limits_{i=1}^n{\sum\limits_{j=1}^m{lcm(i,j)}}\)

     \(=\sum\limits_{i=1}^n{\sum\limits_{j=1}^m{\frac{ij}{gcd(i,j)}}}\)

     \(=\sum\limits_{d=1}{\sum\limits_{i=1}^n{\sum\limits_{j=1}^m{\frac{ij}{d}[gcd(i,j)=d]}}}\)

     \(=\sum\limits_{d=1}{\frac{1}{d}\sum\limits_{i=1}^n{\sum\limits_{j=1}^m{ij[gcd(i,j)=d]}}}\)

于是设

\(f(d)=\sum\limits_{i=1}^n{\sum\limits_{j=1}^m{ij[gcd(i,j)=d]}}\)

\(F(d)=\sum\limits_{i=1}^n{\sum\limits_{j=1}^m{ij[d \mid gcd(i,j)]}}\)

显然

\(F(d)=\sum\limits_{d \mid d'}f(d')=\sum\limits_{i=1}^{\frac{n}{d}}{\sum\limits_{j=1}^{\frac{m}{d}}{ijd^2}}\)

反演

\(f(d)=\sum\limits_{d \mid d'}{\mu(\frac{d'}{d})F(d')}\)

\(\therefore ans=\sum\limits_{d=1}{\frac{1}{d}f(d)}\)

       \(=\sum\limits_{d=1}{\frac{1}{d}\sum\limits_{d \mid d'}{\mu(\frac{d'}{d})F(d')}}\)

       \(=\sum\limits_{d=1}{\frac{1}{d}\sum\limits_{k=1}{\mu(k)F(dk)}}\)

       \(=\sum\limits_{d=1}{\frac{1}{d}\sum\limits_{k=1}{\mu(k)\sum\limits_{i=1}^{\frac{n}{dk}}{\sum\limits_{j=1}^{\frac{m}{dk}}{ijd^2k^2}}}}\)

       \(=\sum\limits_{d=1}{d\sum\limits_{k=1}{k^2\mu(k)\sum\limits_{i=1}^{\frac{n}{dk}}{\sum\limits_{j=1}^{\frac{m}{dk}}{ij}}}}\)

所以把自然数的前缀和及\(k^2\mu(k)\)预处理出来即可分块套分块解决,时间复杂度\(O(n)\)

\({\frak{code:}}\)

#include<bits/stdc++.h>
#define IL inline
using namespace std;
const int N=1e7+3,p=20101009;
int n,m,ans,sum[N],mu[N],vis[N],pri[N];
IL int in(){
    char c;int f=1;
    while((c=getchar())<'0'||c>'9')
      if(c=='-') f=-1;
    int x=c-'0';
    while((c=getchar())>='0'&&c<='9')
      x=x*10+c-'0';
    return x*f;
}
IL void mod(int &x){if(x>=p) x-=p;}
IL void Mod(int &x){if(x<0) x+=p;}
void pre(int n){
    mu[1]=sum[1]=1;
    for(int i=2;i<=n;++i){
        mod(sum[i]=sum[i-1]+i);
        if(!vis[i]) pri[++pri[0]]=i,mu[i]=-1;
      for(int j=1,k;(k=i*pri[j])<=n;++j){
        vis[k]=1;
        if(i%pri[j]) mu[k]=-mu[i];
        else break;
        }
    }
    for(int i=1;i<=n;++i) mu[i]=1ll*mu[i]*i*i%p,mod(mu[i]+=mu[i-1]),Mod(mu[i]);
}
IL int get(int n,int m){
    int res=0;
    for(int l=1,r;l<=n;l=r+1){
        r=min(n/(n/l),m/(m/l));
        mod(res+=1ll*sum[n/l]*sum[m/l]%p*(mu[r]-mu[l-1]+p)%p);
    }
    return res;
}
int main()
{
    n=in(),m=in();
    if(n>m) swap(n,m);
    pre(m);
    for(int l=1,r;l<=n;l=r+1){
        r=min(n/(n/l),m/(m/l));
        mod(ans+=1ll*get(n/l,m/l)*(sum[r]-sum[l-1]+p)%p);
    }
    cout<<(ans%p+p)%p<<endl;
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/yiqiAtiya/p/12158903.html