GCD(i,j)求和 (莫比乌斯函数)(CJOJ2512)

题意:

∑ i = 1 n ∑ j = 1 m g c d ( i , j ) \sum_{i=1}^n\sum_{j=1}^mgcd(i,j) i=1nj=1mgcd(i,j)
n,m=1e7


O ( N ) O(N) O(N)版本:

换成因子角度,设: g c d ( i , j ) = d , m i n ( n , m ) = N gcd(i,j)=d,min(n,m)=N gcd(i,j)=d,min(n,m)=N,有: A n s = ∑ d = 1 N d ∑ i = 1 n ∑ j = 1 m [ g c d ( i , j ) = = d ] = ∑ d = 1 N d ∑ i = 1 n d ∑ j = 1 m d [ g c d ( i , j ) = = 1 ] Ans=\sum_{d=1}^Nd\sum_{i=1}^n\sum_{j=1}^m[gcd(i,j)==d]=\sum_{d=1}^Nd\sum_{i=1}^{\frac{n}{d}}\sum_{j=1}^{\frac{m}{d}}[gcd(i,j)==1] Ans=d=1Ndi=1nj=1m[gcd(i,j)==d]=d=1Ndi=1dnj=1dm[gcd(i,j)==1] g c d = = d gcd==d gcd==d按照套路可以进行莫比乌斯的倍数反演: g ( d , n , m ) = ∑ i = 1 n ∑ j = 1 m [ g c d ( i , j ) = = d ] 构 造 : f ( d , n , m ) = ∑ d ∣ D g ( D , n , m ) = ∑ i = 1 n ∑ j = 1 m [ d ∣ g c d ( i , j ) ] = [ n d ] [ m d ] 反 演 : g ( d , n , m ) = ∑ d ∣ D m i n ( n , m ) u ( D d ) f ( D ) = ∑ d ∣ D m i n ( n , m ) u ( D d ) [ n D ] [ m D ] 而 我 们 所 求 为 g c d = = 1 , 所 以 : g ( 1 , n , m ) = ∑ i = 1 N u ( i ) [ n i ] [ m i ] A n s = ∑ d = 1 N d ∗ g ( 1 , n d , m d ) A n s = ∑ d = 1 N d ∑ i = 1 N d u ( i ) [ n i ∗ d ] [ m i ∗ d ] g(d,n,m)=\sum_{i=1}^n\sum_{j=1}^m[gcd(i,j)==d] \\ 构造:f(d,n,m)=\sum_{d|D}g(D,n,m)=\sum_{i=1}^n\sum_{j=1}^m[d|gcd(i,j)]=[\frac{n}{d}][\frac{m}{d}]\\反演:g(d,n,m)=\sum_{d|D}^{min(n,m)}u(\frac{D}{d})f(D)=\sum_{d|D}^{min(n,m)}u(\frac{D}{d})[\frac{n}{D}][\frac{m}{D}]\\而我们所求为gcd==1,所以:g(1,n,m)=\sum_{i=1}^Nu(i)[\frac{n}{i}][\frac{m}{i}]\\Ans=\sum_{d=1}^Nd*g(1,\frac{n}{d},\frac{m}{d})\\Ans=\sum_{d=1}^Nd\sum_{i=1}^\frac{N}{d}u(i)[\frac{n}{i*d}][\frac{m}{i*d}] g(d,n,m)=i=1nj=1m[gcd(i,j)==d]f(d,n,m)=dDg(D,n,m)=i=1nj=1m[dgcd(i,j)]=[dn][dm]g(d,n,m)=dDmin(n,m)u(dD)f(D)=dDmin(n,m)u(dD)[Dn][Dm]gcd==1g(1,n,m)=i=1Nu(i)[in][im]Ans=d=1Ndg(1,dn,dm)Ans=d=1Ndi=1dNu(i)[idn][idm]同样,到这里两个分块时间复杂度为O(N)

#include
using namespace std;
#define LL long long
const int  N = 1e7+9;
const LL mod = 998244353;
LL u[N];
LL pri[N>>1],now;
bool vis[N];
void init(){                            //预处理莫比乌斯函数前缀和
    vis[1]=1;u[1]=1;
    for(int i=2;i<N;i++){
        if(!vis[i])pri[++now]=i,u[i]=-1;
        for(int j=1;j<=now&&pri[j]*i<N;j++){
            vis[pri[j]*i]=1;
            u[pri[j]*i]=-u[i];
            if(i%pri[j]==0){u[pri[j]*i]=0;break;}
        }
    }
    for(int i=1;i<N;i++)u[i]=u[i]+u[i-1];
}

LL solve(LL n,LL m){
    LL ans=0;
    LL NN=min(n,m);
    for(LL l=1,r;l<=NN;l=r+1){          //[(n/d)/i][(m/d)/i] 分块
        r=min(n/(n/l),m/(m/l));
        LL re=(u[r]-u[l-1])*(n/l)%mod*(m/l)%mod ;
        ans=(ans+re)%mod;
    }
    return (ans+mod)%mod;
}

int main(){
    init();
    LL n,m;
    while(cin>>n>>m){
        LL NN=min(n,m);
        LL ans=0;
        for(LL l=1,r;l<=NN;l=r+1){      //N/d 分块
            r=NN/(NN/l);
            LL d=(l+r)*(r-l+1)/2%mod;
            LL re=solve(n/l,m/l);
            re=(re+mod)%mod;
            ans=(ans+d*re%mod)%mod;
        }
        printf("%lld\n",ans);
    }
}

你可能感兴趣的:(数论/数学,例题)