bzoj 2186: [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取模后的值

本题其实不算一个难题,题意显然就是要求在N!内与M!互质的数的个数,我们先来看在M!内与M!互质的数,很显然就是一个欧拉函数,可以线性的求出,那么在N!内呢?显然如果i与M!是互质的,那么i+M!也与M!互质,i+2×M!也与M!互质,那么在N!内与M!互质的个数=φ(M!)×N!/M! (mod r),所以我们的目的就变成了求出这个式子,,又由于φ(M!)=M!×(p1-1)/p1×(p2-1)/p2……,所以式子又可化为N!×∏(pi-1)/pi (mod r),其中pi指的是M!的不同质因子,显然这个式子中,N!(mod r)可以O(n)预处理,而∏(pi-1)/pi也是可以O(n)预处理的,所以可以O(预处理),O(1)查询;
下面我们来看看∏(pi-1)/pi的求法,假设我们令a[m]表示∏(pi-1)/pi (mod r),pi为m!的质因子,那么我们可以分情况讨论,当m为质数时,那么m!的质因子与(m-1)!的质因子只有一个不同,那就是多了一个m,所以此时a[m]=a[m-1]×m%r×inv(m%r)%r(除了inv里的%r都是为了防溢出的),而如果m不为质数,那么m!的质因子与(m-1)!的质因子是完全一样的,不同的只是某个因子的指数,所以此时a[m]=a[m-1];至此,∏(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);
    }
}

你可能感兴趣的:(数论,逆元,线性筛)