zoukankan      html  css  js  c++  java
  • 【CJOJ2512】gcd之和(莫比乌斯反演)

    【CJOJ2512】gcd之和(莫比乌斯反演)

    题面

    给定(n,m(n,m<=10^7))

    [sum_{i=1}^nsum_{j=1}^mgcd(i,j) ]

    题解

    首先把公因数直接提出来

    [sum_{d=1}^ndsum_{i=1}^{n/d}sum_{j=1}^{m/d}[gcd(i,j)==1] ]

    很明显

    [f(x)=sum_{i=1}^{a}sum_{j=1}^{b}[gcd(i,j)==x] ]

    [g(x)=sum_{x|d}f(d) ]

    [g(x)=sum_{i=1}^{a}sum_{j=1}^{b}[x|gcd(i,j)] ]

    [g(x)=sum_{i=1}^{a/x}sum_{j=1}^{b/x}[1|gcd(i,j)] ]

    [g(x)=[frac{a}{x}]·[frac{b}{x}] ]

    很明显,可以对(f(x))进行莫比乌斯反演,

    [f(x)=sum_{i=1}^xmu(i)g(i) ]

    可以数论分块算

    所求的式子

    [ans=sum_{d=1}^{n}df(1) ]

    其中,对于每一次计算的(a,b)
    (a=[frac{n}{d}],b=[frac{m}{d}])
    这个也很显然可以数论分块

    最后,总体复杂度(O(n))

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<set>
    #include<map>
    #include<vector>
    #include<queue>
    using namespace std;
    #define MOD 998244353
    #define MAX 10000000
    inline int read()
    {
    	int x=0,t=1;char ch=getchar();
    	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    	if(ch=='-')t=-1,ch=getchar();
    	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    	return x*t;
    }
    int n,m;
    bool zs[MAX+1000];
    int pri[MAX+1000],tot,mu[MAX+1000],smu[MAX+1000];
    long long ans;
    void pre()
    {
    	zs[1]=true;mu[1]=1;
    	for(int i=2;i<=MAX;++i)
    	{
    		if(!zs[i])pri[++tot]=i,mu[i]=-1;
    		for(int j=1;j<=tot&&i*pri[j]<=MAX;++j)
    		{
    			zs[i*pri[j]]=true;
    			if(i%pri[j]==0){mu[i*pri[j]]=0;break;}
    			else mu[i*pri[j]]=-mu[i];
    		}
    	}
    	for(int i=1;i<=MAX;++i)smu[i]=(smu[i-1]+mu[i])%MOD;
    }
    int Solve(int a,int b)
    {
    	int i=1,j;
    	long long ret=0;
    	while(i<=a)
    	{
    		j=min(a/(a/i),b/(b/i));
    		ret+=1ll*(smu[j]-smu[i-1]+MOD)%MOD*(a/i)%MOD*(b/i)%MOD;
    		ret%=MOD;
    		i=j+1;
    	}
    	return (ret+MOD)%MOD;
    }
    int main()
    {
    	n=read();m=read();
    	if(n>m)swap(n,m);
    	int i=1,j;
    	pre();
    	while(i<=n)
    	{
    		j=min(n/(n/i),m/(m/i));
    		int tt=1ll*(i+j)*(j-i+1)/2%MOD;
    		ans+=1ll*tt*Solve(n/i,m/i);
    		ans%=MOD;
    		i=j+1;
    	}
    	printf("%lld
    ",(ans+MOD)%MOD);
    	return 0;
    }
    
    
  • 相关阅读:
    leetcode-19-merge
    leetcode-18-remove
    R-codes-tips
    python-bioInfo-codes-2
    Java-framework-Vaadin
    leetcode-17-BST
    生物信息学-知识笔记-1
    leetcode-16-greedyAlgorithm
    perl-tips-1
    计算机网络HTTP、TCP/IP包
  • 原文地址:https://www.cnblogs.com/cjyyb/p/8260593.html
Copyright © 2011-2022 走看看