传送门!
题目在这里…
题目大意?
难道不是说的很清楚了么OvO
求n!中与m!互质的数的个数..
题目分析.
显然的数论… 所以就是化式子呗..
一个很显然的性质就是如果
gcd(a,b)=1
,那么
gcd(a+kb,b)=1
…
而题目中说了
m⩽n
, ∴
m!|n!
于是我们只需要计算
m!
中与
m!
互质的数的个数,然后乘以
n!m!
即可..
我们发现上面加粗的这一坨就是
φ(m!)
嘛…
所以
ans=φ(m!)∗n!m!
又有
φ(x)=x∗∏ni(1−1pi)
其中
pi
表示x的质因数…
而
m!=1∗2∗...∗m
, 所以
m!
的质因数很显然就是不大于
m
的质数…
然后带入上式约掉
由于多组询问, 而且内存开了256MB不是 所以我们要预处理… 不然会T…
由于上式, 我们要预处理的东西有:
- 筛素数(简单欧拉筛)
- 阶乘(顺着乘一遍取模就行了)
- 逆元(要递推求出所有数的哦) (所以最好用
O(n)
的, 不会的话直接看代码就行了 百度一下一堆详细讲解OvO)
-
muli=∏nipi−1pi
这一坨东西…(不大于
m
的质数
然后处理这一坨的时候也很容易…递推即可.. 显然, 我们有
1. 当
i
是质数时,
2. 否则
muli=muli−1
即可…
这样就做完了.
实现代码:
#include <cstdio>
typedef long long LL;
const int X=1e7+3;
inline int gn(int a=0,char c=0){
for(;c<48||c>57;c=getchar());
for(;c>47&&c<58;c=getchar())
a=a*10+c-48; return a;
}
int inv[X],fac[X],eu[X],mul[X],pri[X/10],tot;
bool notp[X]; int T,R,M,N;
void prime(){
notp[1]=1;
for(int i=2;i<X;++i){
if(!notp[i])pri[++tot]=i;
for(int j=1;j<=tot&&i*pri[j]<=1e7;++j){
notp[i*pri[j]]=1; if(i%pri[j]==0) break;
}
}
}
void calcinv(){
inv[1]=1;
for(int i=2;i<X;++i){
inv[i]=(LL)(R-R/i)*inv[R%i]%R;
if(inv[i]<0) inv[i]+=R;
}
}
void calcfac(){
fac[1]=1;
for(int i=2;i<X;++i)
fac[i]=(LL)fac[i-1]*i%R;
}
void calcmul(){
mul[1]=1;
for(int i=2;i<X;++i)
if(!notp[i]) mul[i]=(LL)mul[i-1]*(i-1)%R*inv[i]%R;
else mul[i]=mul[i-1];
}
int main(){
T=gn(),R=gn();
prime(); calcinv(); calcfac(); calcmul();
while(T--){
N=gn(),M=gn();
printf("%d\n",(int)((LL)fac[N]*mul[M]%R));
}
}
注意事项~
- 做乘法的时候要转long long,(当然你要是全用long long算当我没说
- 预处理的时候1的值作为边界值给出, 循环要从2开始
- 每一步都记得取模
- 输出的时候记得换行而不是空格(我是不是暴露了什么←_←