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

本文介绍了一种求解特定数论求和问题的方法,该问题涉及求两个变量的乘积形式的欧拉函数之比,并对其结果进行素数模运算。通过将问题转化为求最大公约数及其欧拉函数的乘积形式,利用莫比乌斯反演和分块技术实现了高效求解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description

a=1mb=1nφ(ab)φ(a)φ(b)∑a=1m∑b=1nφ(ab)φ(a)φ(b)

Input

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

(1T3,1n,m106,max(m,n)<p109+7)

Output

输出答案,结果模pp​

Sample Input

1
5 7 23

Sample Output

2

Solution

假设a=pa11...parrqb11...qbss,b=pc11...pcrrqd1s+1...qdts+ta=p1a1...prarq1b1...qsbs,b=p1c1...prcrqs+1d1...qs+tdt,其中p1,...,pr,q1,...,qs+tp1,...,pr,q1,...,qs+t为互不相同的素数,那么有φ(ab)=abi=1r(11pi)j=1s+t(11qj)φ(ab)=ab∏i=1r(1−1pi)∏j=1s+t(1−1qj),而φ(a)φ(b)=ab(i=1r(11pi))2j=1s+t(11qj)φ(a)φ(b)=ab(∏i=1r(1−1pi))2∏j=1s+t(1−1qj),故有

φ(ab)φ(a)φ(b)=1i=1r(11pi)=gcd(a,b)φ(gcd(a,b))φ(ab)φ(a)φ(b)=1∏i=1r(1−1pi)=gcd(a,b)φ(gcd(a,b))

那么答案即为
i=1mj=1ngcd(i,j)φ(gcd(i,j))=d=1min(m,n)dφ(d)f(md,nd)∑i=1m∑j=1ngcd(i,j)φ(gcd(i,j))=∑d=1min(m,n)dφ(d)⋅f(⌊md⌋,⌊nd⌋)

其中f(m,n)f(m,n)表示满足1am,1bn,gcd(a,b)=11≤a≤m,1≤b≤n,gcd(a,b)=1的二元组(a,b)(a,b)的对数

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

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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值