因为我没有BZOJ的权限号,所以我的代码只是过了样例,所以具体的细节我也不知道过没有,所以看我博客的同学要是不麻烦的话可以交一下我的代码。。
Description
神犇YY虐完数论后给傻×kAc出了一题
给定N, M,求1<=x<=N, 1<=y<=M且gcd(x, y)为质数的(x, y)有多少对
kAc这种傻×必然不会了,于是向你来请教……
多组输入
Input
第一行一个整数T 表述数据组数
接下来T行,每行两个正整数,表示N, M
Output
T行,每行一个整数表示第i组数据的结果
Sample Input
2
10 10
100 100
10 10
100 100
Sample Output
30
2791
2791
HINT
T = 10000
N, M <= 10000000
题解: 这个题还是老套路就是还是把f(n)当成gcd(x,y)=n有多少对,那么我们就能很明显的看出F(n)的含义,就是n|gcd(x,y)的数量。
所以的话刚开始的时候我们还是应该先把方程写下来的,这样子的话我们才能根据方程进行公式推导,我们先把重要的方程写下来。。
待续
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=10000001;
ll mu[N],g[N];
int vis[N],prime[N];
int cnt;
void Init()
{
memset(vis,0,sizeof(vis));
mu[1] = 1;
cnt = 0;
for(int i=2; i<N; i++)
{
if(!vis[i])
{
prime[cnt++] = i;
mu[i] = -1;
}
for(int j=0; j<cnt&&i*prime[j]<N; j++)
{
vis[i*prime[j]] = 1;
if(i%prime[j]) mu[i*prime[j]] = -mu[i];
else
{
mu[i*prime[j]] = 0;
break;
}
}
}
g[1]=0;
for(int i=0;i<cnt;i++)
{
for(int j=prime[i];j<N;j+=prime[i])
{
g[j]+=mu[j/prime[i]];
}
}
for(int i=1;i<N;i++) g[i]+=g[i-1];
}
void slove(int n,int m)
{
if(n>m) swap(n,m);
ll ans=0;
int r;
for(int i=1;i<=n;i=r+1)
{
r=min(n/(n/i),m/(m/i));
ans+=(g[r]-g[i-1])*(n/i)*(m/i);
}
cout<<ans<<endl;
}
int main()
{
int t;
int n,m;
Init();
scanf("%d",&t);
for(int i=1;i<=t;i++)
{
scanf("%d%d",&n,&m);
slove(n,m);
}
}