题目描述
神犇YY虐完数论后给傻×kAc出了一题
给定N, M,求1<=x<=N, 1<=y<=M且gcd(x, y)为质数的(x, y)有多少对
kAc这种傻×必然不会了,于是向你来请教……
多组输入
输入输出格式
输入格式:
第一行一个整数T 表述数据组数
接下来T行,每行两个正整数,表示N, M
输出格式:
T行,每行一个整数表示第i组数据的结果
输入输出样例
输入样例#1:
2
10 10
100 100
输出样例#1:
30
2791
说明
T = 10000
N, M <= 10000000
分析:终于搞定了这一题,反演题目真的好难呀,不看题解真的不会做。
题解:网址
代码:
#include
#include
#include
#define LL long long
const int maxn=1e7+5;
using namespace std;
LL mu[maxn],h[maxn],prime[maxn],sum[maxn];
bool not_prime[maxn];
int n,m,test,cnt;
void get_mu(int n)
{
mu[1]=1;
for (int i=2;i<=n;i++)
{
if (!not_prime[i])
{
prime[++cnt]=i;
mu[i]=-1;
}
for (int j=1;j<=cnt;j++)
{
if (prime[j]*i>n) break;
not_prime[i*prime[j]]=1;
if (i%prime[j]==0)
{
mu[i*prime[j]]=0;
break;
}
mu[i*prime[j]]=-mu[i];
}
}
for (int i=1;i<=cnt;i++)
for (int j=prime[i];j<=n;j+=prime[i])
h[j]+=mu[j/prime[i]];
for (int i=1;i<=n;i++) sum[i]=sum[i-1]+h[i];
}
LL ask(int n,int m)
{
if (n>m) swap(n,m);
int t;
LL ans=0;
for (int i=1;i<=n;i=t+1)
{
t=min(n/(n/i),(m/(m/i)));
ans+=(LL)(n/i)*(m/i)*(sum[t]-sum[i-1]);
}
return ans;
}
int main()
{
scanf("%d",&test);
get_mu(10000000);
while (test--)
{
scanf("%d%d",&n,&m);
printf("%lld\n",ask(n,m));
}
}