代码实现一些数学操作
又是一发学习笔记。
这次和以往有点不同,以前的学习笔记是纯数学干货,这次是代码。
备注:exgcd在Chapter III “快速”类别里。不要找不到就说这里没有了然后骂街
Chapter I 筛法
埃筛
#define maxn 1000000
bool isp[maxn+1];
void eratos(int n){
memset(isp,true,sizeof(isp));
isp[0]=isp[1]=false;
for(int i=2;i<=n;i++){
if(isp[i]){
for(int j=i*i;j<=n;j+=i) isp[j]=false;
}
}
}
欧拉筛
bool isp[10001];int p[10001];
void Eulersieve(int n){
memset(isp,true,sizeof(isp));
p[0]=0;
for(int i=2;i<=n;i++){
if(isp[i]) p[++p[0]]=i;
for(int j=1;j<=p[0]&&i*p[j]<=n;j++){
isp[i*p[j]]=false;
if(i%p[j]==0) break;
}
}
}
Chapter III 欧拉函数
欧拉函数
int Eulerphi(int n){
int res=n;
for(int i=2;i*i<=n;i++){
if(n%i==0){
res=res/i*(i-1);
for(;n%i==0;n/=i);
}
}
if(n!=1) res=res/n*(n-1);
return res;
}
范围求欧拉函数
int euler[2<<30];
void EulerphiPLUS(int n){
for(int i=0;i<n;i++) euler[i]=i;
for(int i=2;i<n;i++){
if(euler[i]==i){
for(int j=i;j<n;j+=i) euler[j]=euler[j]/i*(i-1);
}
}
}
Chapter III 快速
拓展gcd
由于快速求出一元二次方程,所以也归类在“快速”里
int exgcd(int a,int b,int &x,int &y){
if(b==0){
x=1;
y=0;
return a;
}else{
int d=exgcd(b,a%b,y,x);
y-=a/b*x;
return d;
}
}
快速幂
void ksm(int a,int b,int p){
int ans=1;
while(b!=0){
if(b&1)
ans=ans*a%p;
a=a*a%p;
b>>=1;
}
return ans%p;
}
Chapter IV 逆元
线性逆元
注意:需要p为质数
int inv[1000000];
void getinv(int x,int p){
inv[1]=1;
for(int i=2;i<=x;i++)
inv[i]=(p-p/i)*(inv[p%i])%p;
}
利用exgcd求逆元,不需要m为质数
前置:exgcd
int get_inverse(int a,int m){
int x,y,d;
d=exgcd(a,m,x,y);
if(d!=1) return 0;
else return (x+m)%m;
}
阶乘逆元
前置:快速幂
注意:需要p为质数
#define N 10005
int fac[N];
int finv[N];//阶乘的逆元
void init(int n,int p){
fac[0]=1;
for(int i=1;i<=n;i++){
fac[i]=fac[i-1]*i%p;
}
finv[n]=ksm(fac[n],p-2,p);
for(int i=n;i>=1;i--){
finv[i-1]=finv[i]*i%p;
}
}
黑科技阶乘逆元
同样需要让p为质数
finv[1]=1;
for(int i=2;i<=n;i++){
finv[i]=(mod-mod/i)*finv[mod%i]%mod;
}
fac[0]=finv[0]=1;
for(int i=1;i<=n;i++){
fac[i]=fac[i-1]*i%mod;
finv[i]=finv[i]*finv[i-1]%mod;
}
本质上是线性的逆元,直接乘起来。
Chapter V 组合
p为质数时求组合取模
前置:快速幂
#define lll long long
lll C(lll a,lll b,lll p){
if(a==b||b==0)
return 1;
if(b>a-b){
b=a-b;
}
lll x=1;
lll y=1;
for(lll i=(a-b+1);i<=a;i++){
x=x*i%p;
}
for(lll i=1;i<=b;i++){
y=y*i%p;
}
return (x*ksm(y,p-2,p))%p;
}
无预处理组合数
前置:快速幂
注意:需要p为质数
#define lll long long
lll C(lll a,lll b,lll p){
if(a==b||b==0)
return 1;
if(b>a-b){
b=a-b;
}
lll x=1;
lll y=1;
for(lll i=(a-b+1);i<=a;i++){
x=x*i%p;
}
for(lll i=1;i<=b;i++){
y=y*i%p;
}
return (x*ksm(y,p-2,p))%p;
}
预处理组合数
注意:
#define mod 998244353
int q;int n,m,k;
int c[N][N];
void init(int x,int y){
for(int i=0;i<=a;i++){
for(int j=0;j<=b;j++){
if(!j)
c[i][j]=1;
else
c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod;
}
}
}
lucas定理(原)
前置:组合数
注意:需要p为质数
LL Lucas(LL n,LL m,LL p){
if(n<m)
return 0;
if(!n)
return 1;
return Lucas(n/p,m/p,p)*C(n%p,m%p,p)%p;
}
中国剩余定理
前置:快速幂
注意:需要p为质数
int b[N];//模数
void crt(int n){
int val;
fo(i,1,n)
val=(val+a[i]*(mod/b[i])%mod*ksm(mod/b[i],b[i]-2,b[i]))%mod;
return val;
}