版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Ronaldo7_ZYB/article/details/89524946
题目描述
给定N, M,求1<=x<=N, 1<=y<=M且gcd(x, y)为质数的(x, y)有多少对。
其中数据加强,N和M将近1000w。
题解
根据莫比乌斯反演公式,则一定有:
我们对于所求的答案
,有:
然后再对这一个
算式变形一下:用T来枚举这一份i*d,则有:
.
我们另 ,我们只要能够快速的求出T(i)就能够很快的得到答案。
我们可以在线性筛结束的时候求解这一个t(i),大致是这样的:
for (int i=1;i<=m;++i)
for (int j=1;prime[i]*j<=n;++j)
f[prime[i]*j] += Miu[j];
在这其中, 枚举的是每一个质数, 枚举的是每一个数中, 中除去 的值。
代码如下:
#include <bits/stdc++.h>
using namespace std;
const int N = 10000015;
int f[N];
int sum[N];
int Miu[N];
int vis[N];
int prime[N];
void Get_Miu(int n)
{
int m = 0;
Miu[1] = 1;
for (int i=2;i<=n;++i)
{
if (vis[i] == 0) prime[++m] = i, Miu[i] = -1;
for (int j=1;j<=m && i*prime[j]<=n;++j)
{
vis[i*prime[j]] = 1;
if (i%prime[j] == 0) break;
Miu[i*prime[j]] = -Miu[i];
}
}
for (int i=1;i<=m;++i)
for (int j=1;prime[i]*j<=n;++j)
f[prime[i]*j] += Miu[j];
return;
}
void Get_sum(int n)
{
for (int i=1;i<=n;++i)
sum[i] = sum[i-1]+f[i];
return;
}
void work(void)
{
int n,m,j;
long long ans = 0;
scanf("%d %d",&n,&m);
for (int i=1;i<=min(n,m);i=j+1)
{
j = min(n/(n/i),m/(m/i));
ans += (long long)(sum[j]-sum[i-1])*(n/i)*(m/i);
}
printf("%lld\n",ans);
return;
}
int main(void)
{
Get_Miu(N-10);
Get_sum(N-10);
int n;
cin>>n;
while (n -- ) work();
return 0;
}