hdu 多校数论 GuGuFishtion

容斥+gcd+欧拉函数

求出1-n 和 1-m所有gcd(i,j)==x对数

x的范围1-min(n,m)

分解x的质因子 (1-1/p)...

q[x]=(1-1/p1)*(1-1/p2)/...

p是x的质因子

ans=sigma(q[x]*gcd(i,j)==x的对数) 1<=x<=min(n,m)

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<vector>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=1e6+5;
int phi[maxn],vis[maxn],pre[maxn],top;
ll num[maxn],q[maxn];
ll f[maxn],g[maxn];
ll qpow(ll a,ll b,ll c)
{
    ll ans=1;
    while(b)
    {
        if(b&1)
            ans=ans*a%c;
        a=a*a%c;
        b>>=1;
    }
    return ans;
}
void init()
{
    int i,j;
    for(i=1; i<maxn; i++)
        phi[i]=i;
    for(i=2; i<maxn; i+=2)
        phi[i]/=2;
    for(i=3; i<maxn; i+=2)
        if(phi[i]==i)
        {
            for(j=i; j<maxn; j+=i)
                phi[j]=phi[j]/i*(i-1);
        }
    top=0;
    memset(vis,0,sizeof(vis));
    for(i=2; i<maxn; i++)
    {
        if(!vis[i])
        {
            pre[top++]=i;

        }
        for(j=0; pre[j]*i<maxn; j++)
        {
            vis[pre[j]*i]=1;
            if(i%pre[j]==0)
                break;
        }
    }
}
void init1(ll p)
{
    int i,j,k;
    for(i=0; i<top; i++)
    {
        k=pre[i];
        q[k]=qpow(pre[i]-1,p-2,p);
        q[k]=1ll*q[k]*(pre[i])%p;
    }
    for(i=1; i<maxn; i++)
        num[i]=1;
     for(i=0;i<top;i++)
     {
         for(j=pre[i];j<maxn;j+=pre[i])
            num[j]=1ll*num[j]*q[pre[i]]%p;
     }
}
int main()
{
    int i,j,k,t,n,m,z;
    ll ans,p;
    scanf("%d",&t);
    init();
    while(t--)
    {
        scanf("%d%d%I64d",&m,&n,&p);
        init1(p);
        memset(f,0,sizeof(f));
        memset(g,0,sizeof(g));
        z=min(n,m);
        for(i=1; i<=z; i++)
            f[i]=1ll*(n/i)*(m/i)%p;
        ll sum;
        for(i=z; i>=1; i--)
        {
            sum=0;
            for(j=i+i; j<=z; j+=i)
            {
                sum+=g[j];
                sum=sum%p;
            }
            g[i]=(f[i]-sum+p)%p;
        }
        ans=0;
        for(i=1; i<=z; i++)
        {
            ans+=1ll*g[i]*num[i]%p;
            ans=ans%p;
        }
        printf("%I64d\n",ans%p);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/liweiggg/p/9475286.html