• P2257 YY的GCD


    洛谷题目链接

    第一道自己认真做的数论

    有两种方法,默认((N<M))

    方法一:

    我们需要求:$$sumlimits_{i=1}^N sumlimits_{j=1}^M [gcd(i,j)=prime]$$

    我们会想到枚举其中的素数:$$sumlimits_{p epsilon prime} sumlimits_{i=1}^N sumlimits_{j=1}^M [gcd(i,j)=p]$$

    再一步变形:$$sumlimits_{p epsilon prime} sumlimits_{i=1}^N sumlimits_{j=1}^M [gcd(frac{i}{p},frac{j}{p})=1]$$

    [sumlimits_{p epsilon prime} sumlimits_{i=1}^{leftlfloor frac{N}{p} ight floor} sumlimits_{j=1}^{leftlfloorfrac{M}{p} ight floor} [gcd(i,j)=1] ]

    是不是看到中括号里面的东西想到了什么?莫比乌斯函数~~

    因为莫比乌斯函数的性质:$$sumlimits_{d|n} mu (d)=[n=1]$$

    所以原式可化为:$$sumlimits_{p epsilon prime} sumlimits_{i=1}^{leftlfloorfrac{N}{p} ight floor} sumlimits_{j=1}^{leftlfloorfrac{M}{p} ight floor} sumlimits_{d|gcd(i,j)} mu (d)$$

    我们按照套路把(d)提前,其中(d|gcd(i,j))这个条件可以转化成(d|i,d|j),我们就枚举(d):$$sumlimits_{p epsilon prime} sumlimits_{d=1}^{leftlfloorfrac{N}{p} ight floor} mu (d) sumlimits_{i=1}^{leftlfloorfrac{N}{p} ight floor} [d|i] sumlimits_{j=1}^{leftlfloorfrac{M}{p} ight floor} [d|j]$$

    根据整出分块,没学过的可以看看我的其他博客,我们就可以把最后两个(sum)消去了:$$sumlimits_{p epsilon prime} sumlimits_{d=1}^{leftlfloorfrac{N}{p} ight floor} mu (d) leftlfloor frac{N}{d imes p} ight floor leftlfloor frac{M}{d imes p} ight floor$$

    这里我们再用一个小技巧,我们用(T)代替(d imes p)

    [sumlimits_{p epsilon prime} sumlimits_{T=1}^N mu (frac{T}{p}) leftlfloor frac{N}{T} ight floor leftlfloor frac{M}{T} ight floor ]

    稍微变一下:$$sumlimits_{T=1}^N sumlimits_{p epsilon prime} mu (frac{T}{p}) leftlfloor frac{N}{T} ight floor leftlfloor frac{M}{T} ight floor$$

    这样的话,我们就先线性筛出(mu)函数,然后把(sumlimits_{p epsilon prime} mu (frac{T}{p}))处理出来,做一下前缀和,就可以用整除分块来(O(sqrt n))回答每个询问了

    接下来是美滋滋的代码时间~~~

    #include<iostream>
    #include<cstdio>
    #define N 10000007
    #define int long long
    using namespace std;
    int T,n,m,ans,cnt;
    int mu[N],prime[N>>2],num[N];
    bool isp[N];
    void Get_mu()
    {
    	mu[1]=1;
    	for(int i=2;i<=N-7;++i)
    	{
    		if(!isp[i])
    		{
    			prime[++cnt]=i;
    			mu[i]=-1;
    		}
    		for(int j=1;j<=cnt&&(prime[j]*i)<=N-7;++j)
    		{
    			isp[i*prime[j]]=1;
    			if(i%prime[j]==0)
    				break;
    			else
    				mu[i*prime[j]]=-mu[i];
    		}
    	}
    	for(int i=1;i<=cnt;++i)
    	{
    		int res=1;
    		for(int j=prime[i];j<=N-7;j+=prime[i],++res)
    			num[j]+=mu[res];
    	}
    	for(int i=2;i<=N-7;++i)
    		num[i]+=num[i-1];
    }
    signed main()
    {
    	Get_mu();
    	scanf("%lld",&T);
    	while(T--)
    	{
    		scanf("%lld%lld",&n,&m);
    		if(n>m)
    			swap(n,m);
    		ans=0;
    		for(int l=1,r;l<=n;l=r+1)
    		{
    			r=min(n/(n/l),m/(m/l));
    			ans+=(num[r]-num[l-1])*(n/l)*(m/l);
    		}
    		printf("%lld
    ",ans);
    	}
    	return 0;
    }
    

    方法二:

    我们要求:$$sumlimits_{i=1}^N sumlimits_{j=1}^M [gcd(i,j)=prime]$$

    我们设(F(d))表示(d|gcd(i,j))(1<=i<=N,1<=j<=M)((i,j))对数

    很明显:$$F(d)=sumlimits_{i=1}^N sumlimits_{j=1}^M [d|gcd(i,j)]$$

    (d|gcd(i,j))可以化为(d|i,d|j):$$F(d)=sumlimits_{i=1}^N [d|i] sumlimits_{j=1}^M [d|j]$$

    [=leftlfloor frac{N}{d} ight floor leftlfloor frac{M}{d} ight floor ]

    我们再设(f(d))表示(gcd(i,j)=d)(1<=i<=N,1<=j<=M)((i,j))对数

    可得$$F(d)=sumlimits_{d|n}^N f(n)$$

    莫比乌斯反演得:$$f(d)=sumlimits_{d|n}^N mu (frac{n}{d}) F(n)$$

    而我们题目中就是要求:$$Ans=sumlimits_{p epsilon prime} f(p)$$

    (f(p))带入:$$Ans=sumlimits_{p epsilon prime} sumlimits_{p|d} mu (frac{d}{p}) leftlfloor frac{N}{d} ight floor leftlfloor frac{M}{d} ight floor$$

    我们改为枚举(frac{d}{p}):$$Ans=sumlimits_{p epsilon prime} sumlimits_{d=1}^{leftlfloor frac{N}{p} ight floor} mu (d) leftlfloor frac{N}{d imes p} ight floor leftlfloor frac{M}{d imes p} ight floor$$

    那么再像上面那个方法一样用(T)代替(d imes p)即可

    代码也是一样的~~~

  • 相关阅读:
    代理模式与Android
    图数据库 Titan 高速入门
    怎样编写支持命令行选项的程序
    协方差的意义
    我所理解的Spring AOP的基本概念
    Google搜索解析
    POJ 3311 Hie with the Pie floyd+状压DP
    JS怎样将拖拉事件与点击事件分离?
    C++语言笔记系列之十二——C++的继承
    Mac下Android配置及unity3d的导出Android
  • 原文地址:https://www.cnblogs.com/yexinqwq/p/11104889.html
Copyright © 2020-2023  润新知