这道题的算法含精量特别高,而且十分有趣。如果你会了这道题,那么你的排列算法就很厉害了。
一.算法预备
1.筛法
有托筛和欧筛,反正就是把所有素数给找出来,并存在一起。
(1)埃筛(慢一些)
void seive (int n){
for (int i = 2; i <= n; i ++){
if (! vis[i]){
prime[++ pn] = i;
for (int j = i * 2; j <= n; j += i)
vis[j] = 1;
}
}
}
(2)欧筛(快一些)
void seive (int n){
for (int i = 2; i <= n; i ++){
if (! vis[i])
prime[++ pn] = i;
for (int j = 1; j <= pn && i * prime[j] <= n; j ++){
vis[i * prime[j]] = 1;
if (i % prime[j] == 0)
break;
}
}
}
2. 预处理阶乘法
就是预处理出每一个素数的阶乘(等一下在题目中讲)。
3.逆元
逆元广泛用于除运算和模运算同时出现的地方。因为不能边除边模,所以要用逆元,即:
代码:
LL niyuan (LL n){//快速幂+逆元
LL ans = 1, y = p - 2;
while (y > 0){
if (y % 2 == 1)
ans = ans * n % p;
n = n * n % p;
y /= 2;
}
return