2186: [Sdoi2008]沙拉公主的困惑
Time Limit: 10 Sec Memory Limit: 259 MB
Submit: 2568 Solved: 860
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!互质的数量。。
预处理出1…10000000的逆元和素数。。
都可以线性筛。。
phi(m!) * ( n! / m!)
phi (m!) = m! * (p-1)/p p是m!的质因数
附上本蒟蒻的代码:
#include<cstdio>
#include<cmath>
using namespace std;
#define N 10000000
int T,R,n,m,tot,fac[10000001],inv[10000001],prime[10000001],ans[10000001];
bool mark[10000001];
int read()
{
int w=0,c=1; char ch=getchar();
while (ch<'0' || ch>'9')
{
if (ch=='-') c=-1;
ch=getchar();
}
while (ch>='0' && ch<='9')
w=w*10+ch-'0',ch=getchar();
return w*c;
}
void exgcd(int a,int b,int &x,int &y)
{
int t;
if (!b)
{
x=1,y=0;
return;
}
exgcd(b,a%b,x,y),t=x,x=y,y=t-(a/b)*y;
}
int getinv(int t)
{
int x,y;
exgcd(t,R,x,y);
return (x%R+R)%R;
}
void solve()
{
int i,j;
fac[1]=1;
for (i=2;i<=N;i++) fac[i]=(long long)fac[i-1]*i%R;
inv[1]=1;
for (i=2;i<=N;i++)
{
if (!mark[i]) prime[++tot]=i,inv[i]=getinv(i);
for (j=1;prime[j]*i<=N && j<=tot;j++)
{
mark[prime[j]*i]=1;
if (i%prime[j]==0) break;
}
}
ans[1]=1;
for (i=2;i<=N;i++)
{
ans[i]=ans[i-1];
if (!mark[i]) ans[i]=(long long)ans[i]*(i-1)%R*inv[i]%R;
}
}
int main()
{
T=read(),R=read();
solve();
while (T--)
{
n=read(),m=read();
printf("%d\n",(long long)fac[n]*ans[m]%R);
}
return 0;
}