分析:
//详情参见problem B
很明显,如果
(“()”表示最大公因数)
那么
那么如果
将
唯一分解:
然后发现,若x存在某个质因子
,且y存在同样的一个质因子
,那么它们的乘积中就有
这个质因子。
根据
函数的定义:
那么对于
的贡献为
对于
的贡献为
对于
的贡献为
发现:
所以,定义
那么
所以只需要枚举一下gcd=g,然后求所有gcd为g的方案数即可。莫比乌斯反演一下就出来了。。(其实用不着反演,直接用莫比乌斯函数的性质上去容斥就可以了)
#include<cstdio>
#include<cstring>
#include<algorithm>
#define SF scanf
#define PF printf
#define MAXN 1000000
using namespace std;
typedef long long ll;
int tot;
int primes[MAXN+10],isprime[MAXN+10],minp[MAXN+10],mu[MAXN+10];
ll fspx[MAXN+10];
ll p,n,m;
ll fsp(ll x,int y){
ll res=1;
while(y){
if(y&1)
res=res*x%p;
x=x*x%p;
y>>=1;
}
return res;
}
void prepare(){
mu[1]=1;
for(int i=2;i<=MAXN;i++){
if(isprime[i]==0){
primes[++tot]=i;
minp[i]=i;
mu[i]=-1;
}
for(int j=1;primes[j]*i<=MAXN;j++){
isprime[i*primes[j]]=1;
if(i%primes[j]==0){
minp[i*primes[j]]=primes[j];
mu[i*primes[j]]=0;
break;
}
minp[i*primes[j]]=primes[j];
mu[i*primes[j]]=-mu[i];
}
}
for(int i=1;i<=MAXN;i++)
mu[i]=mu[i-1]+mu[i];
}
int t;
ll ans;
ll work(ll x,ll y){
if(x>y)
swap(x,y);
ll last=0,res=0;
for(ll i=1;i<=x;i=last+1){
last=min(x/(x/i),y/(y/i));
res+=1ll*(x/i)*(y/i)%p*(mu[last]-mu[i-1])%p;
res%=p;
}
return (res+p)%p;
}
ll solve(ll x){
ll x1=x;
ll s=1;
ll s1=1;
while(x!=1ll){
if(s1%minp[x]!=0){
(s*=1ll*minp[x]*fspx[minp[x]]%p)%=p;
s1*=minp[x];
}
x/=minp[x];
}
ll sumx=work(n/x1,m/x1);
ll res=sumx*s%p;
return res;
}
int main(){
prepare();
SF("%d",&t);
while(t--){
ans=0;
SF("%I64d%I64d%I64d",&n,&m,&p);
for(int i=1;i<=tot&&primes[i]<=min(n,m);i++){
fspx[primes[i]]=fsp(primes[i]-1,p-2);
}
for(int i=2;i<=min(n,m);i++){
//PF("{%d %lld}\n",i,solve(i));
(ans+=solve(i))%=p;
}
(ans+=work(n,m))%=p;
ans=(ans+p)%p;
PF("%I64d\n",ans);
}
}