当前位置: 代码迷 >> 综合 >> BZOJ2186 [Sdoi2008]沙拉公主的困惑
  详细解决方案

BZOJ2186 [Sdoi2008]沙拉公主的困惑

热度:32   发布时间:2023-12-14 17:06:26.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取模后的值

Sample Input

1 11

4 2

Sample Output

1

数据范围:

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

题意:求1àN!中与M!互质的个数

分析:我们要求的答案就是φ(m!)*(n!)/(m!)%p

有关答案的推导(http://blog.csdn.net/PoPoQQQ/article/details/39957117

而φ(m!)=m!*(pi-1)/pi  pi为m!的质因数

所以我们最后的结果就是n!*∏(pi-1)/pi

那么需要求1到1e7的素数和逆元

Code

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define dep(i,a,b) for(int i=a;i>=b;i--)
#define LL long long
#define mem(x,num) memset(x,num,sizeof x)
using namespace std;
inline LL read()
{LL f=1,x=0;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;
}
const int maxn=1e7+6;
LL ans[maxn],fac[maxn],inv[maxn],n,m,T,cnt=0,mod;
int prime[1000000];
bool not_prime[maxn];
void shaker()
{LL j;rep(i,2,maxn){if(!not_prime[i])prime[++cnt]=i;for(j=1;j<=cnt&&i*prime[j]<=maxn;j++){not_prime[prime[j]*i]=1;if(i%prime[j]==0)break;}}fac[1]=inv[1]=1;rep(i,2,maxn)fac[i]=fac[i-1]*i%mod;rep(i,2,maxn){if(i==mod)break;inv[i]=(mod-mod/i)*inv[mod%i]%mod;}ans[1]=1;rep(i,2,maxn)if(!not_prime[i])ans[i]=ans[i-1]*(i-1)%mod*inv[i%mod]%mod;else ans[i]=ans[i-1];
}
int main()
{T=read(),mod=read();shaker();while(T--){n=read(),m=read();printf("%lld\n",fac[n]*ans[m]%mod);}return 0;
}