题面
题目可简化为求:
\[\displaystyle\sum_{i=1}^{n!}{[gcd(i,m!)=1]}(1到n!中,所有与m!互质的数的个数) \]
如何求解:
首先假设有\(gcd(a,b) = 1\),则一定有\(gcd(a+b,b)=1\)。
所以考虑把\(n!\)分为\(\frac{n!}{m!}\)块,其中\(m \leq n\),所以\(n!\) mod \(m!\) 一定等于\(0\),即我们分出的一定是整数块。
而且其中每一块中与\(m!\)互质的数的个数一定是相等的。
此时我们的式子为:
\[\frac{n!}{m!}\times\displaystyle\sum_{i=1}^{m!}[gcd(i,m!)=1] \]
其中
\[\displaystyle\sum_{i=1}^{m!}[gcd(i,m!)=1] \]
等等,是不是看着有点眼熟?小于等于\(m!\)的正整数中与\(m!\)互质的数的数目...不就是欧拉函数的定义吗?
那这不就是\(\varphi(m!)\)吗?
于是我们的式子就可以完美的变为:
\[\frac{n!}{m!}\times\varphi(m!) \]
因为求\(\varphi(i)\)的公式为:
\[\varphi(i)=i\times\frac{p_1-1}{p_1}\times...\times\frac{p_x-1}{p_x}(p为i的所有质因数) \]
把\(\varphi(i)\)换为\(\varphi(m!)\)代进\(\frac{n!}{m!}\times\varphi(m!)\)去展开:
\[\frac{n!}{m!}\times\varphi(m!)=\frac{n!}{m!}\times m!\times\frac{p_1-1}{p_1}\times...\times\frac{p_x-1}{p_x} \]
于是我们的式子就可以化简为:
\[n!\times\frac{p_1-1}{p_1}\times...\times\frac{p_x-1}{p_x} \]
注意此时\(p\)为\(m!\)的所有质因数。
那么我们的问题就转化为求:
\[n!\times\frac{p_1-1}{p_1}\times...\times\frac{p_x-1}{p_x} \]
\(n!\)好求,对于\(\frac{p_1-1}{p_1}\times...\times\frac{p_x-1}{p_x}\)我们线性求出逆元即容易求出。
线性预处理出来\(1\)到\(maxn\)的所有\(i!\)和\(\frac{p_1-1}{p_1}\times...\times\frac{p_x-1}{p_x}\)即可\(O(1)\)的询问。
时间复杂度为\(O(1e7+t)\)。
由蒟蒻代码自带大常数+某谷评测机不稳定,有时候能过有时候不能过,开了\(O_2\)稳过。
代码:
#include
using namespace std;
templatevoid read(temp &x){
x = 0;temp f = 1;char ch;
while(!isdigit(ch = getchar())) (ch == '-') and (f = -1);
for(x = ch^48; isdigit(ch = getchar()); x = (x<<1)+(x<<3)+(ch^48));
return (void)(x *= f);
}
template void read(temp& a, Args& ...args){read(a), read(args...);}
const int maxn = 1e7+10;
int t, mod, n, m, cnt, prime[maxn];
long long inv[maxn], fac[maxn], fi[maxn];
bool is_prime[maxn];
void memset_mine(){
fac[0] = fac[1] = inv[0] = inv[1] = fi[0] = fi[1] = 1;
for(int i = 2; i <= maxn; i ++){
fac[i] = (fac[i-1]*i)%mod, inv[i] = mod-mod/i*inv[mod%i]%mod;
fi[i] = fi[i-1];
if(!is_prime[i]) prime[++cnt] = i, fi[i] = (fi[i]%mod*(i-1)%mod*inv[i]%mod)%mod;
for(int j = 1; j <= cnt and i*prime[j] <= maxn; j ++){
is_prime[i*prime[j]] = 1;
if(!(i%prime[j])) break;
}
}
}
signed main(){
read(t, mod);
memset_mine();
while(t --){
read(n, m);
printf("%lld\n", fac[n]%mod*fi[m]%mod);
}
return 0;
}
没啦qwq。