原题:hdu 6390
题意:
定义 G(a,b)=ϕ(a∗b)ϕ(a)∗ϕ(b)(ϕ(i)为欧拉函数), G ( a , b ) = ϕ ( a ∗ b ) ϕ ( a ) ∗ ϕ ( b ) ( ϕ ( i ) 为 欧 拉 函 数 ) , 求:
解析:
欧拉函数的公式为:
那么易得:
那么我们要处理的就是 gcd(a,b)=i g c d ( a , b ) = i 时的 G(a,b)值 G ( a , b ) 值 ,以及有多少对a,b的gcd为i
一 : 求 gcd(a,b)=i g c d ( a , b ) = i 时的 G(a,b)值 G ( a , b ) 值 |
G(a,b)=ϕ(i)/i, G ( a , b ) = ϕ ( i ) / i , 所以我们可以用预处理欧拉函数差不多的方法预处理出G值
for(D i=2;i<=MAXN;i++){// v为G值
inv[i]=(mod-mod/i)*inv[mod%i]%mod;//处理逆元
if(!vis[i]){
pri[++now]=i;
v[i]=i*inv[i-1]%mod;//质数的G
}
for(D j=1;j<=now&&pri[j]*i<=MAXN;j++){
vis[i*pri[j]]=1;
if(i%pri[j]==0){
v[i*pri[j]]=v[i];// i|pri[j]那么i*pri[j]的质因子==i的质因子
break;
}
v[i*pri[j]]=v[i]*v[pri[j]]%mod;//i没包括pri[j]这个质因子的时候
}
}
二 : 求 a∈[1,n],b∈[1,m]有多少对(a,b)的gcd为i a ∈ [ 1 , n ] , b ∈ [ 1 , m ] 有 多 少 对 ( a , b ) 的 g c d 为 i |
对于一个数i,在 a∈[1,n],b∈[1,m] a ∈ [ 1 , n ] , b ∈ [ 1 , m ] 的范围内, 设f[i]为gcd为(i,2i,3i...)的对数 设 f [ i ] 为 g c d 为 ( i , 2 i , 3 i . . . ) 的 对 数
显然 : f[i]=[n/i]∗[m/i] f [ i ] = [ n / i ] ∗ [ m / i ]
那么我们从大到小维护 f[i] f [ i ] ,因为我们要的是 gcd=i g c d = i 的对数,所以要把 gcd=2i g c d = 2 i 的情况减去
for(D i=1;i<=MAXN;i++){
f[i]=(n/i)*(m/i)%mod;
}
for(D i=MAXN/2;i>=1;i--){//最高到MAXAN/2有2i的情况
for(D j=i+i;j<=MAXN;j+=i){
f[i]-=f[j];
if(f[i]<0)f[i]+=mod;
}
}
代码:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<string>
#include<cstring>
#include<algorithm>
#include<set>
#include<map>
#include<list>
#include<vector>
#include<stack>
#include<queue>
#include<ctime>
#include<cstdlib>
#include<sstream>
#include<functional>
using namespace std;
#define D long long
#define F double
#define mmm(a,b) memset(a,b,sizeof(a))
D read(){ D ans=0; char last=' ',ch=getchar();
while(ch<'0' || ch>'9')last=ch,ch=getchar();
while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
if(last=='-')ans=-ans; return ans;
}
const int N=1000000;
const F pi=acos(-1);
D n,m,p,mi;
D f[N+9],v[N+9],inv[N+9];
D pri[N+9],now;
bool vis[N+9];
void init(){
mmm(vis,0);mi=min(m,n);now=0;
for(D i=1;i<=mi;i++){
f[i]=(n/i)*(m/i)%p;
}
for(D i=mi/2;i>=1;i--){
for(D j=i+i;j<=mi;j+=i){
f[i]-=f[j];
if(f[i]<0)f[i]+=p;
}
}
v[1]=inv[1]=1;
for(D i=2;i<=mi;i++){
inv[i]=(p-p/i)*inv[p%i]%p;
if(!vis[i]){
pri[++now]=i;
v[i]=i*inv[i-1]%p;
}
for(D j=1;j<=now&&pri[j]*i<=mi;j++){
vis[i*pri[j]]=1;
if(i%pri[j]==0){
v[i*pri[j]]=v[i];
break;
}
v[i*pri[j]]=v[i]*v[pri[j]]%p;
}
}
}
int main(){
int t=read();
while(t--){
n=read(),m=read(),p=read();
init();
D ans=0;
for(D i=1;i<=mi;i++)
ans=(ans+f[i]*v[i])%p;
printf("%lld\n",ans);
}
}