题意
有一个M * N的表格,行与列分别是1 - M和1 - N,格子中间写着行与列的最大公约数Gcd(i, j)(1 <= i <= M, 1 <= j <= N)。
给出M和N,求这张表中有多少个质数。
T<=1000,n,m<=5000000
分析
比较好的思路。
[p]
表示若p为素数则为1否则为0.
∑p∑i=1⌊np⌋∑j=1⌊mp⌋[gcd(i,j)=1][p]
=∑p∑i=1⌊np⌋∑j=1⌊mp⌋∑k|i,k|jμ(k)[p]
=∑k=1n∑p=1⌊nk⌋∑i=1⌊nkp⌋∑j=1⌊nkp⌋μ(k)[p]
=∑k=1n∑p=1⌊nk⌋⌊nkp⌋⌊nkp⌋μ(k)[p]
=∑T=1n⌊nT⌋⌊mT⌋∑k|Tμ(Tk)[k]
代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
const int N=5000005;
int mu[N],prime[N],tot;
bool not_prime[N];
LL f[N];
void get_prime(int n)
{
mu[1]=1;
for (int i=2;i<=n;i++)
{
if (!not_prime[i]) prime[++tot]=i,mu[i]=-1;
for (int j=1;j<=tot&&i*prime[j]<=n;j++)
{
not_prime[i*prime[j]]=1;
if (i%prime[j]==0) break;
mu[i*prime[j]]=-mu[i];
}
}
for (int i=1;i<=tot;i++)
{
int x=prime[i];
for (int j=x;j<=n;j+=x) f[j]+=mu[j/x];
}
for (int i=1;i<=n;i++) f[i]+=f[i-1];
}
LL solve(int n,int m)
{
LL ans=0;
for (int i=2,last;i<=n;i=last+1)
{
last=min(n/(n/i),m/(m/i));
ans+=(LL)(n/i)*(m/i)*(f[last]-f[i-1]);
}
return ans;
}
int main()
{
get_prime(5000000);
int T;
scanf("%d",&T);
while (T--)
{
int n,m;
scanf("%d%d",&n,&m);
if (n>m) swap(n,m);
printf("%lld\n",solve(n,m));
}
return 0;
}