若 ( a , m ) = 1 (a,m)=1 (a,m)=1,使得 a x ≡ 1 ( m o d m ) a^x \equiv 1(mod \ m) ax≡1(mod m) 成立的最小的 x x x,称为 a a a关于模 m m m的阶,记为 o r d m a ord_ma ordma 。
若 ( g , m ) = 1 (g,m)=1 (g,m)=1,且 o r d m g = φ ( m ) ord_mg=\varphi(m) ordmg=φ(m),则 g g g为 m m m的一个原根。
质因数分解, p , k p,k p,k分别表示分解后的质因数和对应的幂。
void prime_fac(int x,VI &p,VI &k)
{
for(int i=2;i*i<=x;i++)
if(x%i==0)
{
p.push_back(i);
int q=0;
while(x%i==0) q++,x/=i;
k.push_back(q);
}
if(x>1) p.push_back(x),k.push_back(1);
}
若 p p p为素数,则 C n m % p = C n / p m / p ⋅ C n % p m % p % p C_n^m\%p=C_{n/p}^{m/p} \cdot C_{n\%p}^{m\%p} \%p Cnm%p=Cn/pm/p⋅Cn%pm%p%p 。常用于大数小模数的组合数计算。
LL lucas(LL n,LL m,LL p) //卢卡斯定理(p是素数)
{
if(!m) return 1;
return C(n%p,m%p)*lucas(n/p,m/p)%p;
}
扩展卢卡斯定理(exLucas):
对于 p p p不是素数的情况,首先进行质因数分解,然后对每一块分别求答案之后用CRT合并答案。
每一块虽然不一定是质数(是质数的幂),但是通过阶乘变形可以找到规律然后递归求解。
...(pit)
用于求解 ∑ i = 1 n ⌊ n i ⌋ \sum_{i=1}^{n} \lfloor\frac{n}{i}\rfloor ∑i=1n⌊in⌋ 。
核心思想是对于任意的 i i i,找到最大的 j j j,使得 ⌊ n i ⌋ = ⌊ n j ⌋ \lfloor\frac{n}{i}\rfloor=\lfloor\frac{n}{j}\rfloor ⌊in⌋=⌊jn⌋ ,可以证明 j = ⌊ n ⌊ n i ⌋ ⌋ j=\lfloor\frac{n}{\lfloor\frac{n}{i}\rfloor}\rfloor j=⌊⌊in⌋n⌋ 。所以可以在 O ( n ) O(\sqrt{n}) O(n) 的时间内求解。
对于多个取整相乘同时分块的话(比如 ∑ i = 1 n ⌊ n i ⌋ ⌊ m i ⌋ \sum_{i=1}^{n}\lfloor\frac{n}{i}\rfloor\lfloor\frac{m}{i}\rfloor ∑i=1n⌊in⌋⌊im⌋),显然每次的 j j j 就取最小那个。
int cal(int n)
{
int ans=0;
for(int l=1,r=0;l<=n;l=r+1)
{
r=n/(n/l);
ans+=(r-l+1)*(n/l);
}
return ans;
}
莫比乌斯函数定义:
μ ( n ) = { 1 , n = 1 0 , n 有 平 方 因 子 ( − 1 ) k , k 为 n 的 质 因 子 个 数 \mu(n) = \left\{\begin{array}{lr} 1 ,& n=1 \\ 0 ,& n有平方因子\\ (-1)^k, & k为n的质因子个数 \end{array}\right. μ(n)=⎩⎨⎧1,0,(−1)k,n=1n有平方因子k为n的质因子个数
线性筛法:
int mu[maxn],prime[maxn],cnt;
bool book[maxn];
void get_mu(int n)
{
mu[1]=1;
for(int i=2;i<=n;i++)
{
if(!book[i]) prime[cnt++]=i,mu[i]=-1;
for(int j=0;j
狄利克雷卷积:设 f ( n ) , g ( n ) f(n),g(n) f(n),g(n)为积性函数,则 f ∗ g = ∑ d ∣ n f ( d ) g ( n d ) f\ast g=\sum_{d|n}f(d)g(\frac{n}{d}) f∗g=∑d∣nf(d)g(dn) 。
反演定理:若 F ( n ) = ∑ d ∣ n f ( d ) F(n)=\sum_{d|n}f(d) F(n)=∑d∣nf(d) ,则 f ( n ) = ∑ d ∣ n μ ( d ) F ( n d ) f(n)=\sum_{d|n}\mu(d)F(\frac{n}{d}) f(n)=∑d∣nμ(d)F(dn) 。(运用卷积很好证明)
另一种形式:若 F ( n ) = ∑ n ∣ d f ( d ) F(n)=\sum_{n|d}f(d) F(n)=∑n∣df(d) ,则 f ( n ) = ∑ n ∣ d μ ( d n ) F ( d ) f(n)=\sum_{n|d}\mu(\frac{d}{n})F(d) f(n)=∑n∣dμ(nd)F(d) 。(pit)
用于求解数论函数的前缀和,在线性筛预处理前面一些项之后,复杂度一般是 O ( n 2 3 ) O(n^\frac{2}{3}) O(n32) 。
比如说要求解 S ( n ) = ∑ i = 1 n f ( i ) S(n)=\sum_{i=1}^{n}f(i) S(n)=∑i=1nf(i) ,套路就是找到好求解的 h = g ∗ f h=g\ast f h=g∗f ,可以演变为:
g ( 1 ) S ( n ) = ∑ i = 1 n ( f ∗ g ) ( i ) − ∑ i = 2 n g ( i ) S ( ⌊ n i ⌋ ) g(1)S(n)=\sum_{i=1}^{n}(f \ast g)(i)-\sum_{i=2}^{n}g(i)S(\lfloor\frac{n}{i}\rfloor) g(1)S(n)=∑i=1n(f∗g)(i)−∑i=2ng(i)S(⌊in⌋)
于是可以递归+数论分块求解。
常用函数前缀和:
一个自然数 p 是素数,当且仅当 ( p − 1 ) ! ≡ − 1 ( m o d p ) (p-1)!\equiv -1 \ (mod \ p) (p−1)!≡−1 (mod p) 。