bzoj 2186: [Sdoi2008] 沙拉公主的困惑 (数论,逆元)

2 篇文章 0 订阅
1 篇文章 0 订阅

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取模后的值

本题其实不算一个难题,题意显然就是要求在N!内与M!互质的数的个数,我们先来看在M!内与M!互质的数,很显然就是一个欧拉函数,可以线性的求出,那么在N!内呢?显然如果i与M!是互质的,那么i+M!也与M!互质,i+2×M!也与M!互质,那么在N!内与M!互质的个数即为

φM!×N!/M!modr
所以我们的目的就变成了求出这个式子,,又由于
φM=M×p11/p1×p21/p2×
所以式子又可化为
N×pi1/pimodr

其中pi指的是M!的不同质因子,显然这个式子中, N!(mod r)可以O(n)预处理,而 ∏(pi-1)/pi也是可以O(n)预处理的,所以可以O(n)预处理,O(1)查询;
下面我们来看看∏(pi-1)/pi的求法,假设我们令a[m]表示∏(pi-1)/pi (mod r),pi为m!的质因子,那么我们可以分情况讨论,当m为质数时,那么m!的质因子与(m-1)!的质因子只有一个不同,那就是多了一个m,所以此时
a[m]=a[m1]×m
而如果m不为质数,那么m!的质因子与(m-1)!的质因子是完全一样的,不同的只是某个因子的指数,所以此时
a[m]=a[m1];
至此,∏(pi-1)/pi我们也在线性时间下算出了,问题也就解决了。

下面是代码:

#include<iostream>
#include<cstdio>
#define M 10000010
using namespace std;
long long f[M],p[M],a[M];
int now=1,top=1,tot=1,r,n,m,prime[500010]; 
bool v[M];
void Mod(int t) {
    for(;top<t;) f[++top]=f[top-1]*(top%r)%r;
}
long long inv(int t) {
    if(t<=tot) return p[t];
    else for(;tot<t;) {
      p[++tot]=(r-r/tot)*p[r%tot]%r;
    } return p[tot];
}
void isprime() {
    for(int i=2;i<M/2;i++) {
      if(!v[i]) prime[++prime[0]]=i;
      for(int j=1;j<=prime[0]&&i*prime[j]<M;j++) {
        v[i*prime[j]]=1; if(!i%prime[j]) break;
      }
    } return;
}
long long ans(int t) {
    if(t<=now) return a[t];
    for(;now<t;) {
      a[++now]=a[now-1];
      if(!v[now]) a[now]=a[now]*(now-1)%r*inv(now%r)%r;
    } return a[t];
}
int main() {
    int T; scanf("%d%d",&T,&r);
    isprime();a[1]=1;p[0]=0;p[1]=1;f[1]=1;
    while(T--) {
      scanf("%d%d",&n,&m); if(n>top) Mod(n);
      printf("%lld\n",f[n]*ans(m)%r);
    }
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值