NKNY寒假培训
[供自己复习,供大家参考]
如果有不对的地方请指出
另外:全文采用int,但实际上平时都是long long请注意
本次培训全是数论题
建议先学“质数基础”做铺垫
(虽然没多大关系)
1. | 欧拉 求phi |
---|---|
2. | Selcet_Euler 求phi |
3. | 线性 求phi |
4. | 扩欧 |
5. | 逆元 |
6. | miller_rabin素数测试 |
7. | 二分快速幂 |
8. | 快速乘法 |
9. | 线性求逆元 |
10. | 中国剩余定理 |
11. | 打表求排列 |
12. | 打表求组合 |
13. | 第二类斯特林数 |
14. | 第一类斯特林数 |
15. | Bell数(懒得写代码) |
16. | 大组合数取模--Lucas定理 |
附录: | 玄学--miller_rabin素数测试 |
1. 欧拉 求phi
int el(int a){
int ans=a;
for(int i=1;i<=a/i;i++){
if(a%i==0){
ans=ans*(i-1)/i;
while(a%i==0)a/=i;
}
}
if(a>1)ans=ans*(i-1)/i;
return ans;
}
2.Selcet_Euler
void Selcet_Euler(int n){
for(int i=1;i<=n;i++)phi[i]=i;
for(int i=2;i<=n;i++){
if(phi[i]==1){
for(int j=1;j<=n;j+=i){
phi[j]=phi[j]/i*(i-1);
}
}
}
}
3. 线性 欧拉 求phi
void gp(){
int tot;
for(int i=2;i<=n;i++){
if(mark[i]==0){
pr[++tot]=i;
phi[i]=i-1;
}
for(int j=1;j<=tot&&pr[j]<=n;j++){
mark[i*pr[j]]=1;
if(i%pr[i]==0){
phi[i*pr[j]]=phi[i]*pr[j];
break;
}else phi[i*pr[j]]=phi[i]*(pr[j]-1);
}
}
}
4.扩欧
int exgcd(int a,int b,int &x,int &y){
int d,temp;
if(b==0){
x=1;
y=0;
return a;
}
d=exgcd(b,a%b,x,y);
temp=x;
x=y;
y=temp-a/b*y;
}
5.逆元
int ni(int a,int n){
int x,y;
if(exgcd(a,n,x,y)==1)return (x+n)%n;
else return -1;
}
6. miller_rabin
bool mr(int n){
int a,x,y,d,r=0;
if(n==2)return 1;
if(n<2||n%2==0)return 0;
d=n-1;
while(d%2==0){
d/=2;
r++;
}
for(int i=1;i<=10;i++){
a=rand()%(n-2)+2;
x=ksm(a,d,n);
for(int i=1;i<=r;i++){
y=x*x%n;
if(y==1&&x!=1&&x!=n-1)return 0;
x=y;
}
if(x!=1)return 0;
}
return 1;
}
7.二分快速幂
int ksm(int a,int b,int mod){
int ans=1;
a%=mod;
while(b){
if(b%2==1)ans=ans*a%mod;
a=a*a%mod;
b/=2;
}
}
8.快速乘法
int ksc(int a,int b,int mod){
int ans=0;
a%=mod;
while(b){
if(b%2==1)ans=(ans+a)%mod;
a=a*2%mod;
b/=2;
}
}
9.线性逆元
inv[0]=inv[1]=1;
for(int i=2;i<=n;i++){
inv[i]=(p-p/i)*inv[p%i]%p;
}
10.中国剩余定理
int china(int *b,int *w,int k){
int d,x,y,ans=0,mi,p=1;
for(int i=1;i<=k;i++)p*=w[i];
for(int i=1;i<=k;i++){
mi=p/w[i];
d=ext_euclid(mi,w[i],x,y);
ans=(ans+x*mi*b[i])%p;
}
if(ans>0)return ans;
else return (ans+p)%p;
}
11.排列
int a[1001][1001];
for(int i=1;i<=n;i++){
a[i][0]=1;
}
for(int i=1;i<=n;i++){
for(int j=1;j<=i;j++){
a[i][j]=(a[i-1][j-1]*i)%k;
//a[i][j]=(a[i-1][j]*(i-j+1))%k;
}
}
12.组合
int c[1001][1001];
for(int i=1;i<=n;i++){
c[i][0]=1;
}
for(int i=1;i<=n;i++){
for(int j=1;j<=i;j++){
c[i][0]=(c[i-1][j]+c[i-1][j-1])%k;
}
}
13.第二类斯特林数
void getStirlng(){
for(int i=1;i<=n;i++)s2[i][1]=1;
for(int i=1;i<=n;i++){
for(int j=2;j<=i&&j<=m;j++){
s2[i][j]=(s2[i-1][j-1]+j*s2[i-1][j])%mod;
}
}
}
14.第一类斯特林数
void getStirlng(){
for(int i=0;i<=n;i++)s1[i][i]=1;
for(int i=1;i<=n;i++){
for(int j=1;j<=i&&j<=m;j++){
s1[i][j]=(s1[i-1][j-1]+(i-1)*s1[i-1][j])%mod;
}
}
}
15. Bell数(懒得写代码了)
按 第二类斯特林数 做
16.大组合数取模--Lucas定理
//Tips:p为全局变量,相当于 mod
int KSM(int a,int b){...}//见上
int C(int a,int b){
if(a<b)return 0;
if(a==b)return 1;
if(b>(a-b))b=a-b;
int A=1,B=1;
for(int i=0;i<b;i++){
A=(A*(a-i))%p;
B=(B*(b-i))%p;
}
return (A*KSM(B,p-2))%p;
}
int lucas(int n,int m){
if(m==0)return 1;
return C(n%p,m%p)*lucas(n/p,m/p);
}
附录:miller_rabin素数测试 毕竟是测试,准确性为
所以!!!
玄学:
时 只需测试a=2,7,61
时 只需测试a=2,3,5,7,11
随机C次 错误率为