HDU 6390 GuGuFishtion(数论+莫比乌斯反演)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/V5ZSQ/article/details/82562851

Description

a = 1 m b = 1 n φ ( a b ) φ ( a ) φ ( b )

Input

第一行一整数 T 表示用例组数,每组用例输入三个整数 n , m , p ,其中 p 是素数

( 1 T 3 , 1 n , m 10 6 , m a x ( m , n ) < p 10 9 + 7 )

Output

输出答案,结果模 p

Sample Input

1
5 7 23

Sample Output

2

扫描二维码关注公众号,回复: 3160651 查看本文章

Solution

假设 a = p 1 a 1 . . . p r a r q 1 b 1 . . . q s b s , b = p 1 c 1 . . . p r c r q s + 1 d 1 . . . q s + t d t ,其中 p 1 , . . . , p r , q 1 , . . . , q s + t 为互不相同的素数,那么有 φ ( a b ) = a b i = 1 r ( 1 1 p i ) j = 1 s + t ( 1 1 q j ) ,而 φ ( a ) φ ( b ) = a b ( i = 1 r ( 1 1 p i ) ) 2 j = 1 s + t ( 1 1 q j ) ,故有

φ ( a b ) φ ( a ) φ ( b ) = 1 i = 1 r ( 1 1 p i ) = g c d ( a , b ) φ ( g c d ( a , b ) )

那么答案即为
i = 1 m j = 1 n g c d ( i , j ) φ ( g c d ( i , j ) ) = d = 1 m i n ( m , n ) d φ ( d ) f ( m d , n d )

其中 f ( m , n ) 表示满足 1 a m , 1 b n , g c d ( a , b ) = 1 的二元组 ( a , b ) 的对数

由莫比乌斯反演及分块加速即可 O ( m i n ( m , n ) ) 得到 f ( m , n ) ,注意到 1 φ ( d ) < m i n ( m , n ) < p ,故可以线性预处理模 p 逆元,时间复杂度 O ( n n )

Code

#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
#define maxn 1000005
int euler[maxn],prime[maxn],res,mu[maxn],sum[maxn];
void get_euler(int n=1e6)
{
    mu[1]=sum[1]=1;
    euler[1]=1;
    res=0;
    for(int i=2;i<=n;i++)
    {
        if(!euler[i])euler[i]=i-1,prime[res++]=i,mu[i]=-1;
        for(int j=0;j<res&&prime[j]*i<=n;j++)
        {
            if(i%prime[j]) 
            {
                euler[prime[j]*i]=euler[i]*(prime[j]-1);
                mu[prime[j]*i]=-mu[i];
            }
            else
            {
                euler[prime[j]*i]=euler[i]*prime[j];
                mu[prime[j]*i]=0;
                break;
            }
        }
        sum[i]=sum[i-1]+mu[i];
    }
}
int T,n,m,p;
int mul(int x,int y)
{
    ll z=1ll*x*y;
    return z-z/p*p;
}
int add(int x,int y)
{
    x+=y;
    if(x>=p)x-=p;
    return x;
}
int inv[maxn];
void init(int n)
{
    inv[0]=0;
    inv[1]=1;
    for(int i=2;i<=n;i++)inv[i]=mul(p-p/i,inv[p%i]);
}
int f(int a,int b)
{
    if(a>b)swap(a,b);
    int ans=0;
    for(int i=1,next=0;i<=a;i=next+1)
    {
        next=min(a/(a/i),b/(b/i));
        int temp=((sum[next]-sum[i-1])%p+p)%p;
        ans=add(ans,mul(mul(a/i,b/i),temp));
    }
    return ans;
}
int main()
{
    get_euler();
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d%d",&n,&m,&p);
        init(min(n,m));
        int ans=0;
        for(int d=1;d<=min(n,m);d++)
        {
            int num=f(n/d,m/d);
            ans=add(ans,mul(mul(d,num),inv[euler[d]]));
        }
        printf("%d\n",ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/V5ZSQ/article/details/82562851