Bzoj2186 [sdoi2008]沙拉公主的困惑

阅读全文大概需要 1分钟
本文总阅读量
Posted by yjjr's blog on February 6, 2018

标签:逆元,筛法,数学,数论

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;
}


本文可以转载,但必须附上原文链接,否则你会终生找不到妹子!!!欢迎关注我的CSDN: ahyjjr