DestinHistoire

 

BZOJ-2186 [Sdoi2008]沙拉公主的困惑(欧拉函数)

题目描述

  求 \(1\) ~ \(n!\) 中与 \(m!\) 互质的数的个数,答案对 \(mod\) 取模。

  数据范围:\(T\leq 10^4,1\leq n,m\leq 10^7,mod\leq 10^9+10\)\(mod\) 是一个质数。

分析

  引理:若 \(\gcd(x,y)=1\),则 \(\gcd(x,y+kx)=1\)(可以用更相减损术证明)。

  把 \([1,n!]\) 分成 \(\frac{n!}{m!}\) 段:\([1,m!],[m!+1,2m!],\cdots,[km!+1,m!]\),由于 \(\gcd(x,m!)=1\),则 \(\gcd(x+km!,m!)\),所以每一段中与 \(m!\) 互质的数都是相同的,有 \(\varphi(m!)\) 个,因此答案为 \(\frac{n!}{m!}\varphi(m!)\),即 \(n!\displaystyle\prod_{i=1}^{k}\frac{1-p_i}{p_i}\),筛法预处理质数,阶乘和 \(\varphi\)

  由于 \(mod\) 未必大于 \(n\),因此 \(1\) ~ \(n\) 中可能有 \(mod\) 的倍数,因此把每个数字都分解成 \(a\times mod^{b}\) 的形式,用两个数组分开记录,在预处理阶乘和欧拉函数时,\(a\) 相乘,\(b\) 相加,最后判断 \(fac2[n]+phi2[m]-fac2[m]\) 是否等于 \(0\) 即可。

代码

#include<bits/stdc++.h>
using namespace std;
const int N=1e7+10;
int prime[N+10],cnt;
bool vis[N+10];
int fac1[N+10],fac2[N+10],phi1[N+10],phi2[N+10];
int n,m,mod;
void init()
{
    vis[1]=1;
    for(int i=2;i<=N;i++)
    {
        if(!vis[i])
            prime[++cnt]=i;
        for(int j=1;i*prime[j]<=N&&j<=cnt;j++)
        {
            vis[i*prime[j]]=1;
            if(i%prime[j]==0)
                break;
        }
    }
    fac1[0]=phi1[0]=1;
    fac2[0]=phi2[0]=0;
    for(int i=1;i<=N;i++)
    {
        int a=i,b=0;
        while(a%mod==0)
        {
            a=a/mod;
            b++;
        }
        fac1[i]=1ll*fac1[i-1]*a%mod;
        fac2[i]=fac2[i-1]+b;
        if(vis[i]==1)
            a=i;
        else
            a=i-1;
        b=0;
        while(a%mod==0)
        {
            a=a/mod;
            b++;
        }
        phi1[i]=1ll*phi1[i-1]*a%mod;
        phi2[i]=phi2[i-1]+b;
    }
}
long long quick_pow(long long a,long long b)
{
    long long ans=1;
    while(b)
    {
        if(b&1)
            ans=ans*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return ans;
}
int main()
{
    int T;
    cin>>T>>mod;
    init();
    while(T--)
    {
        scanf("%d %d",&n,&m);
        long long ans=1ll*fac1[n]*phi1[m]%mod*quick_pow(fac1[m],mod-2)%mod;
        if(fac2[n]+phi2[m]-fac2[m]!=0)
            ans=0;
        printf("%lld\n",ans);
    }
    return 0;
}

posted on 2020-11-29 12:51  DestinHistoire  阅读(58)  评论(0)    收藏  举报

导航