[BZOJ2186][Sdoi2008]沙拉公主的困惑

[Sdoi2008]沙拉公主的困惑

Description
大富翁国因为通货膨胀,以及假钞泛滥,政府决定推出一项新的政策:现有钞票编号范围为1到N的阶乘,但是,政府只发行编号与M!互质的钞票。房地产第一大户沙拉公主决定预测一下大富翁国现在所有真钞票的数量。现在,请你帮助沙拉公主解决这个问题,由于可能张数非常大,你只需计算出对R取模后的答案即可。R是一个质数。
Input
第一行为两个整数T,R。R<=10^9+10,T<=10000,表示该组中测试数据数目,R为模后面T行,每行一对整数N,M,见题目描述 m<=n
Output
共T行,对于每一对N,M,输出1至N!中与M!素质的数的数量对R取模后的值
Sample Input
1 11
4 2
Sample Output
1
数据范围:
对于100%的数据,1 < = N , M < = 10000000

Solution
首先在 [1,M!] 的范围内答案就是 ϕ(M!)
显然 M!1 M $

然后对于大于 M! 的范围,假如一个数 xM!(x>M!)
gcd(x,M!)=1
那么由辗转相除法 gcd(x,M!)=gcd(M!,xmodM!)=1
也就是说它能对应到 [1,M!] 一个与 M!
因此答案就是

N!ϕ(M!)M!

Code

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<typename T>inline void read(T &x){
    x=0; T f=1; char ch=getchar();
    while(!isdigit(ch)) {if(ch=='-') f=-1; ch=getchar();}
    while(isdigit(ch)) {x=x*10+ch-'0'; ch=getchar();}
    x*=f;
}

const ll MaxN=10000001;
int T,tot,n,m;
ll MOD,prime[666666],fac[MaxN],inv[MaxN],phi[MaxN];
bool check[MaxN];

int main(){
    read(T);read(MOD);

    for (int i=2;i<=MaxN;i++){
        if(!check[i]) prime[++tot]=i;
        for (int j=1;j<=tot;j++){
            if(1ll*i*prime[j]>1ll*MaxN) break;
            check[i*prime[j]]=1;
            if(i%prime[j]==0) break;
        }
    }
    fac[1]=inv[1]=phi[1]=1;
    for (int i=2;i<=MaxN;i++) fac[i]=fac[i-1]*i%MOD;
    for (int i=2;i<=MaxN&&i<MOD;i++) inv[i]=(MOD-MOD/i)*inv[MOD%i]%MOD;
    for (int i=2;i<=MaxN;i++)
        if(!check[i]) phi[i]=phi[i-1]*(i-1)%MOD*inv[i%MOD]%MOD;
        else phi[i]=phi[i-1];

    for (;T;T--){
        read(n);read(m);
        printf("%lld\n",fac[n]*phi[m]%MOD); 
    }
    return 0;   
}

你可能感兴趣的:(数论,欧拉函数,辗转相除法)