题目:
题意:
设 ,已知m,n,p,求
。
思路:
欧拉函数性质: (p为质数)。
一个数肯定能表示成若干个质数的乘积,因此,设。
(其余的项上下展开后都可以约掉,因为它们互质)
设 。
设
设
为莫比乌斯函数,有如下性质:
(当n=1时)
(当n>1时)
当gcd(a,b)==1时,,当gcd(a,b)!=1时,
,等价于
。
最后一步的转化中,表示在
中能被d整除的数的个数,
表示在
中能被d整除的数的个数,因此,两者的乘积就表示为在
累加的过程中满足
的情况的个数,因此,最后两个式子等价。
时间复杂度计算:
a[i]数组,欧拉函数,莫比乌斯函数均能线性预处理。
计算的时间复杂度为O(n);
计算的总时间为:
(C为欧拉常数)
因为有n项,所以每项的平均时间为 。
因此,总时间复杂度为 。
代码:
因为的值总是小于 i ,所以预处理 max(m,n) 个逆元已经足够了。
#include <iostream>
#include <string>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <set>
#include <vector>
#include <cstdlib>
#include <algorithm>
using namespace std;
typedef long long ll;
const int MAX = 1e6+10;
ll m,n,mod;
ll prime[MAX],phi[MAX];
int cnt=0;
bool flag[MAX];
int mu[MAX];
ll a[MAX];
ll inv[MAX];
int len;
//预处理欧拉函数phi[ ]和莫比乌斯函数mu[ ]
void init()
{
memset(flag,false,sizeof(flag));
phi[1]=1;
mu[1]=1;
for(int i=2;i<MAX;i++){
if(!flag[i]){
prime[cnt++]=i;
phi[i]=i-1;
mu[i] = -1;
}
for(int j=0;j<cnt&&i*prime[j]<MAX;j++){
flag[i*prime[j]]=true;
if(i%prime[j]==0){
phi[i*prime[j]]=phi[i]*prime[j];
mu[i * prime[j]] = 0;
break;
}
else
phi[i*prime[j]]=phi[i]*(prime[j]-1);
mu[i * prime[j]] = -mu[i];
}
}
}
void gao()
{
//预处理逆元
inv[1]=1;
for(int i=2;i<=len;i++)
inv[i] = 1LL * inv[mod%i]*(mod-mod/i)%mod;
//预处理a[ ]数组 ( a[i]=i/phi[i] )
for(int i=1;i<=len;i++){
a[i]=1ll*i*inv[phi[i]]%mod;
}
}
int main()
{
int T;
scanf("%d",&T);
init();
while(T--)
{
scanf("%lld%lld%lld",&m,&n,&mod);
len=min(m,n);
gao();
ll ans=0;
for(int i=1;i<=len;i++){
int tmp1=m/i,tmp2=n/i;
int v=min(tmp1,tmp2);
//计算g(m/d,n/d)
ll g=0;
for(int j=1;j<=v;j++)
g=(g+1ll*mu[j]*(tmp1/j)*(tmp2/j)+mod)%mod;
ans=(ans+a[i]*g)%mod;
}
printf("%lld\n",ans);
}
return 0;
}