积性函数

当$(n,m) = 1$时有$f(nm) = f(n)f(m)$,则称$f(x)$ 为积性函数。

线性筛法

对于每一个数字$n$,用其最小的质因数筛去,考虑最小质因数 $p$ 与数字 $n$ 的三种情况

1. $n = p$ 。

2. $p|n, p<n$

3. $else$

三种情况分别考虑即可。

以欧拉函数为例:

1. $\phi (i) = i-1$

2. $\phi (tp) = \phi (t) \times p$

3. $\phi (tp) = (p-1) \times \phi(t) $ 这样可以 $O(n)$ 筛出相应函数

例:求出 1~n! 中与 m! 互质的数字个数。

x 与 m! 互质 <-> x 与 1 ~ m 互质 <-> x 不含有 ≤ m的质数。

这样考虑 $x = m!t + k$

$p | x$ <=> $p | k$,这样有 $ans = m! \prod {1 - \frac{1}{p_i}}$

应用阶乘法筛出逆元(用 $(P-1)!^{-1}$ 逆推),预处理出后一部分前缀积,复杂度 $O(n + T)$

#include <iostream>
#include <cstdio>
#include <cstring>

#define LL long long
#define N 10000010

using namespace std;

int tot, prime[N], inv[N], fac[N], P, prev[N];
bool v[N];

int mul(int a,int b)
{
    return a*(LL)b % (LL)P;
}

int qpow(int x,int n)
{
    int ans = 1;
    for(;n;n>>=1,x = mul(x, x))
        if(n&1) ans = mul(ans, x);
    return ans;
}

void init()
{
    fac[0] = 1;
    int nl = min(N,P);
    for(int i=1;i < nl ;i++) fac[i] = mul(fac[i-1], i);
    int tmp = qpow(fac[nl-1], P-2);
    for(int i=nl-1;i>=1;i--)
    {
        inv[i] = mul(tmp, fac[i-1]);
        tmp  = mul(tmp, i);
    }
}

int main()
{
    int T;
    cin>>T>>P;
    init();
    for(int i=2;i<N;i++)
    {
        if(!v[i]) prime[++tot] = i;
        for(int j=1;i*prime[j]<N;j++)
        {
            v[i*prime[j]] = 1;
            if(i%prime[j]==0) break;
        }
    }
    int j = 1;
    prev[0] = 1;
    for(int i=1;i<N;i++)
    {
        prev[i] = prev[i-1];
        if(j<=tot && prime[j]==i)
        {
            prev[i] += P - mul(prev[i] ,inv[i]);
            if(prev[i] >= P) prev[i] -= P;
            j++;
        }
    }
    int n,m;
    while(T--)
    {
        scanf("%d%d",&n,&m);
        printf("%d\n",mul(fac[n], prev[m]));
    }
    return 0;
}
View Code

相关文章:

  • 2021-11-17
  • 2021-08-12
  • 2021-08-10
  • 2021-05-12
  • 2021-12-26
  • 2021-12-28
  • 2022-12-23
  • 2021-12-16
猜你喜欢
  • 2022-02-25
  • 2022-12-23
  • 2021-06-05
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2021-12-07
相关资源
相似解决方案