目录
质数相关
1. 质数判定
2. 质数筛
质数判定
1.O(√N)
2.MillerRobbin
对于大于 2 的素数 n,将 n-1 拆分为 n−1 = 2s∗d 其中 s 和 d 是正整数且 d 是奇数。对所有整数 a,下面两 式一定有一个成立:
(1)
(2)
质数筛
(1)埃氏筛
void fp(int n){
memset(ntp,0,sizeof(ntp));//ntp:是否为合数
for(int i=2;i<=n;i++){
if(ntp[i])continue;
prime[++cnt]=i;
for(int j=i;j<=n/i;j++)
ntp[i*j]=1;
}
}
(2)线性筛
扫描小于 i 的素数表,标记 notp[i*prime[j]]=1,当 prime[j] 是 i 的约数时停止
既保证了每个数都被最小的因数筛去,又保证没有未被筛去的合数(后者滴证明麻烦)
void fp(int n){
memset(ntp,0,sizeof(ntp));
for(int i=2;i<=n;i++){
if(!ntp[i])prime[++cnt]=i;
for(int j=1;j<=cnt&&prime[j]*i<=n;j++){
ntp[prime[j]*i]=1;
if(i%prime[j]==0) break;
}
}
}
(3)区间筛
用来求一个区间内的质数(区间的坐标很大,长度不大)
一个合数 n 一定包含一个不超过 √n 的质因数 用筛法求出 √R 以内的质数 用这些质数去标记 [L,R] 中的合数,未被标记的就是质数
void fi(int l,int r){
memset(ntp1,0,sizeof(ntp));
if(l==1) ntp1[1]=0;
for(int i=1;i<=cnt;i++){
if(prime[i]>sqrt(r))break;
for(int j=(l-1)/prime[i]+1;j<=r/prime[i];j++)//左端向上取整,右端向下取整
if(j>1) ntp2[j*prime[i]-l+1]=1;
}
}
因数相关
- 阶乘因数分解
阶乘因数分解
阶乘 N!中包含质因子 x 的个数为
算术基本定理及扩展
基本定理:
N 的约数个数 =(c1 + 1)∗(c2 + 1)∗…∗(cn + 1)
N 的约数之和 =
的约数之和 =
需要取模时的计算方法:
我们记 若 c 为奇数,则有
若 c 为偶数,则有 递归计算即可。
数值分块
计算k mod 1 +k mod 2 +k mod 3 +……+k mod n
取模相关
求逆元
1.费马小定理
推导得到,即mod为素数时,a的数论逆元为
2.递推法
例题
Combinations
1.求 (1 ≤n,m≤ 5∗105) 的不同质因子个数
分别计算分子和分母中不同质因子的个数,相减大于 0 则对答案贡献 1
#include <iostream>
#include <cstring>
using namespace std;
const int maxn=1e5+5;
int prime[maxn],ntp[maxn],cnt;
int s1[maxn],s2[maxn],s3[maxn];
void fp(int n){
memset(ntp,0,sizeof(ntp));
cnt=0;ntp[1]=1;
for(int i=2;i<=n;i++){
if(!ntp[i]) prime[++cnt]=i;
for(int j=1;j<=cnt&&prime[j]*i<=n;j++){
ntp[prime[j]*i]=1;
if(i%prime[j]==0)break;
}
}
}
void jf(int n,int* s){
for(int i=1;i<=cnt;i++){
int t=prime[i];
int d=n/t;
while(d>0){
s[i]+=d;
d=n/t;
t*=prime[i];
}
}
}
int main(){
fp(50000);
int n,m;
cin>>n>>m;
jf(n,s1);
jf(n-m,s2);
jf(m,s3);
int ans=0;
for(int i=1;i<=cnt;i++)
if(s1[i]>s2[i]+s3[i]) ans++;
cout<<ans<<endl;
}