版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/V5ZSQ/article/details/82562851
Description
求
Input
第一行一整数 表示用例组数,每组用例输入三个整数 ,其中 是素数
Output
输出答案,结果模
Sample Input
1
5 7 23
Sample Output
2
Solution
假设
,其中
为互不相同的素数,那么有
,而
,故有
那么答案即为
其中 表示满足 的二元组 的对数
由莫比乌斯反演及分块加速即可 得到 ,注意到 ,故可以线性预处理模 逆元,时间复杂度
Code
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
#define maxn 1000005
int euler[maxn],prime[maxn],res,mu[maxn],sum[maxn];
void get_euler(int n=1e6)
{
mu[1]=sum[1]=1;
euler[1]=1;
res=0;
for(int i=2;i<=n;i++)
{
if(!euler[i])euler[i]=i-1,prime[res++]=i,mu[i]=-1;
for(int j=0;j<res&&prime[j]*i<=n;j++)
{
if(i%prime[j])
{
euler[prime[j]*i]=euler[i]*(prime[j]-1);
mu[prime[j]*i]=-mu[i];
}
else
{
euler[prime[j]*i]=euler[i]*prime[j];
mu[prime[j]*i]=0;
break;
}
}
sum[i]=sum[i-1]+mu[i];
}
}
int T,n,m,p;
int mul(int x,int y)
{
ll z=1ll*x*y;
return z-z/p*p;
}
int add(int x,int y)
{
x+=y;
if(x>=p)x-=p;
return x;
}
int inv[maxn];
void init(int n)
{
inv[0]=0;
inv[1]=1;
for(int i=2;i<=n;i++)inv[i]=mul(p-p/i,inv[p%i]);
}
int f(int a,int b)
{
if(a>b)swap(a,b);
int ans=0;
for(int i=1,next=0;i<=a;i=next+1)
{
next=min(a/(a/i),b/(b/i));
int temp=((sum[next]-sum[i-1])%p+p)%p;
ans=add(ans,mul(mul(a/i,b/i),temp));
}
return ans;
}
int main()
{
get_euler();
scanf("%d",&T);
while(T--)
{
scanf("%d%d%d",&n,&m,&p);
init(min(n,m));
int ans=0;
for(int d=1;d<=min(n,m);d++)
{
int num=f(n/d,m/d);
ans=add(ans,mul(mul(d,num),inv[euler[d]]));
}
printf("%d\n",ans);
}
return 0;
}