队友告诉我一个结论,phi(ab)/phi(a)phi(b)=gcd(ab)/phi(gcd(a,b)),那么我们发现这道题做完了。枚举gcd就行了,变成了NOI2010能量采集,然而当时我写的复杂度是nsqrt(n),并过不掉这题,于是队友写出了nlogn复杂度,发现还是T。。。于是我找到一篇NOI2010能量采集O(n)的题解https://blog.csdn.net/ThinFatty/article/details/78481516,抄下来改一改就A了= =,phi值先线性预处理一蛤
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn=1e6+5;
LL pri[maxn],phi[maxn],mu[maxn],sum[maxn],cnt,n,m,P;
LL inv[maxn],S[maxn];
bool vis[maxn];
inline void get()
{
phi[1]=1;
mu[1]=1;
cnt=0;
for(int i=2;i<=1e6;++i)
{
if(!vis[i])pri[++cnt]=i,phi[i]=i-1,mu[i]=-1;
for(int j=1;j<=cnt&&i*pri[j]<=1e6;++j)
{
vis[i*pri[j]]=1;
phi[i*pri[j]]=phi[i]*phi[pri[j]];
mu[i*pri[j]]=0;
if(i%pri[j]==0)
{
phi[i*pri[j]]=phi[i]*pri[j];
break;
}
mu[i*pri[j]]-=mu[i];
}
}
}
inline LL calc(LL n,LL m)
{
LL res=0;
for(int i=1,last=0;i<=n;i=last+1)
{
last=min(n/(n/i),m/(m/i));
res+=(sum[last]-sum[i-1])*(n/i)*(m/i);
}
return res;
}
inline LL Pow(LL a,LL b)
{
LL ans=1;
while(b)
{
if(b&1)ans=ans*a%P;
a=a*a%P;
b>>=1;
}
return ans;
}
inline LL sol(LL n,LL m)
{
if(n>m)swap(n,m);
LL ans=0;
inv[0]=inv[1]=1;
int mx=min(P,n);
for(int i = 2; i <= mx; ++i)
inv[i] = (P - (P / i)) * inv[P % i] % P;
for(int i = 1; i<=n ;++i)
S[i]=(S[i-1]+1ll*i*inv[phi[i]]%P)%P;
for (int i=1,last;i<=n;i=last+1)
{
last=min(n/(n/i),m/(m/i));
LL t=(S[last]-S[i-1]+P)%P;
//LL t=(LL)(last+i)*(last-i+1)/2LL;
//printf("%lld\n",calc(n/i,m/i));
//ans+=calc(n/i,m/i,tmp/i)*t;
ans=(ans+1ll*calc(n/i,m/i)%P*t%P)%P;
}
return ans%P;
}
int main()
{
int t;
scanf("%d",&t);
get();
for(int i=1;i<=1e6;++i)sum[i]=sum[i-1]+mu[i];
while(t--)
{
scanf("%lld%lld%lld",&n,&m,&P);
printf("%lld\n",sol(n,m));
}
return 0;
}