• $P2398 GCD SUM$


    (Description)

    (sumlimits_{i=1}^nsumlimits_{j=1}^n gcd(i,j))

    (Solution)

    这种(gcd)计数的题一般思想是枚举(gcd)

    对于这道题,有一下几种做法,循序渐进

    暴力:(O(n^2logn))

    就是暴力枚举所有数求(gcd),期望得分不清楚,大概(20pts)

    可以优化(gcd)函数,记忆化一下。

    画个矩阵发现可以只求下三角,即只求(sumlimits_{i=1}^nsumlimits_{j=1}^{j<i}gcd(i,j)),将答案(*2)后再单独用等差数列求和公式处理对角线上的情况((i==j)),一顿操作猛如虎,但因为会(MLE)仍然无法通过(70pts)

    离正解只差一步的暴力:(O(nsqrt n))

    枚举所有数(i),设组成数对的另一个数为(j),仍是只考虑(i<j)的情况。设(gcd(i,j)=k),则(gcd(frac{i}{k} ,frac{j}{k})=1),符合这样的数(frac{j}{k})的个数就应该是(phi(frac{i}{k})),所以(O(sqrt n))枚举(i)的所有因数为(gcd)(ans+=gcdcdot phi(frac{i}{gcd}))。总复杂度(O(nsqrt n))

    (70pts)肯定是稳过的,至此离正解只差一步。

    正解(O(nln n))

    上面枚举因子(O(sqrt n))显然是可以优化的,可以先枚举(gcd),再枚举另一个因子得出(i=gcd*x),和上面方法是等效的,调和级数(O(ln n))总复杂度(O(n ln n))

    (Code)

    int n,prime[maxn],pcnt,is_not_prime[maxn];
    int phi[maxn];
    ll ans;
    void Get_Phi(int x)
    {
    	is_not_prime[1]=1;
    	for(re int i=2;i<=x;++i)
    	{
    		if(!is_not_prime[i]) prime[++pcnt]=i,phi[i]=i-1;
    		for(re int j=1;j<=pcnt;++j)
    		{
    			if(i*prime[j]>x) break;
    			is_not_prime[i*prime[j]]=1;
    			if(!(i%prime[j]))
    			{
    				phi[i*prime[j]]=phi[i]*prime[j];
    				break;
    			}
    			else phi[i*prime[j]]=phi[i]*phi[prime[j]];
    		}
    	}
    }
    int vis[maxn];
    int main()
    {
        n=read();
        Get_Phi(n);
        for(re int i=1;i<=n;++i)//枚举gcd
    		for(re int j=2;j*i<=n;++j)//枚举数对中较大的数/gcd的结果,从2枚举是为了不考虑对角线 
    		{
    			ans+=(ll)phi[j]*i;
    		}
    	ans*=2;//上三角下三角 
    	ans+=(ll)(1+n)*n/2;//统计对角线 
    	printf("%lld
    ",ans);
    	return 0;
    }
    

    (Updata)

    当我在(luogu)刷这道题的(k)倍经验时,遇到了一道多组数据且(T<=200000)的题,于是成功(TLE)
    其实只需要对上面算法进行小的改动就行

        ans+=(ll)phi[j]*i;
    

    注意到这一行(ans)更新的其实是(sumlimits_{x=1}^{x<i*j}gcd(x,i*j)),相当于对(i*j)的答案更新
    那么可以这样写

        f[i*j]+=(ll)phi[j]*i;
    

    每个答案就是(sumlimits_{i=1}^nf[i])
    所以对于数据个数很多的情况,预处理到最大范围,求前缀和,(O(1))回答即可。

  • 相关阅读:
    接口新建学习---边界提取器
    Android Studio打包.so文件教程
    想要开发好的软件,必须学会这几项!
    你应该首先保护哪些应用程序?这个问题本身问错了!
    几周内搞定Java的10个方法
    翻译:程序员做些业余项目的重要性
    【源码】c#编写的安卓客户端与Windows服务器程序进行网络通信
    10款GitHub上最火爆的国产开源项目
    你的Android应用完全不需要那么多的权限
    2015年移动领域发展的九大趋势
  • 原文地址:https://www.cnblogs.com/Liuz8848/p/11849629.html
Copyright © 2020-2023  润新知