转载地址
线性求逆元原理:
#include <cstdio>
#include <bits/stdc++.h>
#include <map>
#include <cstring>
#include <algorithm>
using namespace std;
#define mst(a,b) memset((a),(b),sizeof(a))
typedef long long ll;
const int maxn = 1000005;
const ll INF = 1e18;
const double eps = 1e-9;
int n,m;
ll p;
char s[maxn];
ll a[maxn];
ll phi[maxn],mu[maxn],inv[maxn];
void euler()
{
phi[1]=1;
for(int i=2;i<maxn;i++)
{
if(!phi[i]){
for(int j=i;j<maxn;j+=i){
if(!phi[j]) phi[j]=j;
phi[j]=phi[j]/i*(i-1);
}
}
}
//求u值
mu[1]=1;
for(int i=1;i<maxn;i++)
for(int j=2*i;j<maxn;j+=i)
mu[j]-=mu[i];
}
void get_inv(int N)
{
//线性求逆元
//begin
inv[1]=1;
for(int i=2;i<N;++i) inv[i]=inv[p%i]*(p-p/i)%p;
//end
for(int i=1;i<N;++i) a[i]=(ll)i*inv[phi[i]]%p;
}
ll get(int n,int m)
{
ll ans=0;
for(int i=1;i<=min(n, m);i++)
{
ans+=(ll)mu[i]*(n/i)*(m/i);
ans%=p;
}
return ans;
}
int main()
{
euler();
int T;
scanf("%d",&T);
for(int kase=1;kase<=T;kase++)
{
scanf("%d%d%lld",&n,&m,&p);
get_inv(min(n,m)+1);
ll ans=0;
for(int i=1;i<=min(n, m);i++)
{
ans+=(ll)a[i]*get(n/i,m/i);
ans%=p;
}
printf("%lld\n",ans);
}
}