洛谷-2155 [SDOI2008]沙拉公主的困惑

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

输入输出样例
输入 #1
1 11
4 2

输出 #1
1

数据范围:
对于100%的数据,1 < = N , M < = 10000000

解释: g c d ( x , y ) = 1 , 则 g c d ( x + k ∗ y , y ) = 1 gcd(x,y)=1,则gcd(x+k*y,y)=1 gcd(x,y)=1,gcd(x+ky,y)=1这是结论。首先 a n s = ∑ i = 1 N ! [ g c d ( i , M ! ) = = 1 ] ans=\sum_{i=1}^{N!}[gcd(i,M!)==1] ans=i=1N![gcd(i,M!)==1]
把它划分为 ( 0 , m ! ] , ( m ! , 2 m ! ] , ( 2 m ! , 3 m ! ] , … , ( k m ! , n ! ] (0,m!],(m!,2m!],(2m!,3m!],…,(km!,n!] (0,m!],(m!,2m!],(2m!,3m!],,(km!,n!]段,由结论知,每一段数的个数相同,所以
a n s = N ! M ! ∗ ∑ i = 1 M ! [ g c d ( i , M ! ) = = 1 ] = N ! M ! ∗ ϕ ( M ! ) ans=\frac{N!}{M!}*\sum_{i=1}^{M!}[gcd(i,M!)==1]=\frac{N!}{M!}*\phi(M!) ans=M!N!i=1M![gcd(i,M!)==1]=M!N!ϕ(M!),根据 ϕ ( M ! ) \phi(M!) ϕ(M!)的定义,可以线性处理出来,就OK

#include <cstdio>
const int N=1e7+5,M=N/10;
int n,R,tot,p[M],ans[N],fac[N],inv[N];
bool flg[N];
void prework(int n) {
    fac[0]=fac[1]=1,inv[0]=inv[1]=1,ans[0]=ans[1]=1;
    for(int i=2;i<=n;++i) {
        fac[i]=1LL*fac[i-1]*i%R,inv[i]=1LL*(R-R/i)*inv[R%i]%R;
        if(!flg[i]) p[++tot]=i;
        for(int j=1;j<=tot&&i*p[j]<=n;++j) {
            flg[i*p[j]]=1;
            if(i%p[j]==0) break;
        }
    }
    for(int i=2;i<=n;++i) {
        ans[i]=ans[i-1];
        if(!flg[i]) ans[i]=1LL*ans[i]*(i-1)%R*inv[i]%R;
    }
}
int main(){
    int T;
    scanf("%d%d",&T,&R);
    prework(N-5);
    while(T--){
        int n,m;
        scanf("%d%d",&n,&m);
        printf("%lld\n",1LL*fac[n]*ans[m]%R);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值