小A的数学题 牛客(莫比乌斯反演)

题目链接: https://ac.nowcoder.com/acm/contest/549/J
题意:
在这里插入图片描述
思路:
在这里插入图片描述
接着1的倍数的 n*m

2的倍数的 n/2*m/2

3的倍数的 n/3*m/3

所以d的倍数的,得减去 2d,3d,4*d,…的结果,最后剩下的就是gcd(i,j)==d的结果了

#include<bits/stdc++.h>
#define mod 1000000007
using namespace std;
typedef long long ll;
const int maxn=1e6+5;
bool check[maxn]; 
int prime[maxn];
int mu[maxn];
void get_mo()
{
	mu[1]=1;
	int cnt=0;
	for(int i=2;i<maxn;i++)
	{
		if(!check[i])
		{
			prime[cnt++]=i;
			mu[i]=-1;
		}
		for(int j=0;j<cnt;j++)
		{
			if(i*prime[j]>maxn)
				break;
			check[i*prime[j]]=true;
			if(i%prime[j]==0){
				mu[i*prime[j]]=0;
				break;
			}
			else
			{
				mu[i*prime[j]]=-mu[i];
			}

		}
	}
}
int main()
{
	int n,m;
	cin>>n>>m;
	get_mo();
	if(n>m)
		swap(n,m);
	ll ans=0;
	for(int i=1;i<=n;i++)
	{
		for(int j=i;j<=n;j+=i)
		{
			ans=(ans+(1ll*i*i%mod)*mu[j/i]*(n/j)*(m/j))%mod;
		}
	}
	cout<<ans<<endl;
	return 0;
}

利用容斥也可做

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=1e6+10;
const int mod=1000000007;
LL f[N];
int main(){
	LL n,m;
	scanf("%lld %lld",&n,&m);
	LL res=0;
	for(int i=min(n,m);i>=1;i--){
		f[i]=(n/i)*(m/i);//这里的括号必须有,要不然,会出错
		for(int j=i*2;j<=min(n,m);j+=i)
			f[i]-=f[j];
		res=(res+f[i]*i%mod*i%mod)%mod;
	}
	printf("%lld\n",res);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_42819598/article/details/89297738