1.素数
c.普通法
/* 普通法求素数 */ #include<iostream> #include<stdio.h> #include<math.h> using namespace std; bool prime(int m) { int i,k; bool flag=true; k=sqrt(m); for(i=2; i<=k; ++i) if(m%i==0) { flag=false; break; } if(flag)return true; return false; } int main() { int i,j; for(i=2; i<100; ++i) if(prime(i))cout<<i<<' '; return 0; }
c2.筛法
/* 筛法求素数 */ #include<iostream> #include<stdio.h> #include<math.h> #include<string.h> using namespace std; int a[1024]; void sieve(int n){//0是素数,-1不是素数 memset(a,0,sizeof(a)); int i,j,k; k=sqrt(n); a[1]=-1; for(i=2;i<=k;++i) if(a[i]==0) for(j=i+i;j<=n;j=j+i) a[j]=-1; } int main(){ int i,n; scanf("%d",&n); sieve(n); for(i=1;i<=n;++i) if(a[i]==0) printf("%d ",i); printf("\n"); return 0; }
kb2.1.1素数筛选(判断<MAXN的数是否素数)
#include<iostream> #include<stdio.h> #include<string.h> using namespace std; /* 素数筛选,判断小于MAXN的数是不是素数。 notprime是一张表,为false表示是素数,true表示不是素数 */ const int MAXN=1000010; bool notprime[MAXN];//值为false表示素数,值为true表示非素数 void init(){ memset(notprime,false,sizeof(notprime)); notprime[0]=notprime[1]=true; int i,j; for(i=2;i<MAXN;++i) if(!notprime[i]){ if(i>MAXN/i)continue;//防止后面i*i溢出(或者i,j用long long) //直接从i*i开始就可以,小于i倍的已经筛选过了,注意是j+=i for(j=i*i;j<MAXN;j+=i) notprime[j]=true; } } int main(){ init(); int i; for(i=0;i<100;++i) if(!notprime[i])printf("%d ",i); return 0; }
kb2.1.2素数筛选(筛选出小于等于MAXN的素数)
#include<iostream> #include<stdio.h> #include<string.h> using namespace std; /* 素数筛选,存在小于等于MAXN的素数 prime[0]存的是素数的个数 */ const int MAXN=100; int prime[MAXN+1]; void getPrime(){ memset(prime,0,sizeof(prime)); int i,j; for(i=2;i<=MAXN;++i){ if(!prime[i])prime[++prime[0]]=i; for(j=1;j<=prime[0]&&prime[j]<=MAXN/i;++j){ prime[prime[j]*i]=1; if(i%prime[j]==0)break; } } } int main(){ getPrime(); int i; for(i=1;i<=prime[0];++i) printf("%d ",prime[i]); return 0; }
2.最大公约数
c.stl
/* stl求最大公约数 */ #include<iostream> #include<stdio.h> #include<bits/stdc++.h> using namespace std; int main(){ int a,b; scanf("%d%d",&a,&b); printf("%d\n",__gcd(a,b)); return 0; }
c2.枚举
/* 枚举求最大公约数 */ #include<iostream> #include<stdio.h> using namespace std; int main(){ int a,b,i; scanf("%d%d",&a,&b); if(a>b){ a=a^b; b=a^b; a=a^b; } for(i=a;i>=1;--i) if(a%i==0&&b%i==0)break; printf("%d\n",i); return 0; }
3.辗转相除法(欧几里德算法)
a
|
b
|
a mod b
|
123456
|
7890
|
5106
|
7890
|
5106
|
2784
|
5106
|
2784
|
2322
|
2784
|
2322
|
462
|
2322
|
462
|
12
|
462
|
12
|
6
|
12
|
6
|
0
|
/* 辗转相除法 迭代形式 */ #include<iostream> #include<stdio.h> using namespace std; int gcd(int a,int b){ int r; while(b!=0){ r=a%b; a=b; b=r; } return a; } int main(){ int a,b; scanf("%d%d",&a,&b); printf("%d\n",gcd(a,b)); return 0; }
递归:
/* 辗转相除法 递归 */ #include<iostream> #include<stdio.h> using namespace std; int gcd(int a,int b){ if(b==0)return a; return gcd(b,a%b); } int main(){ int a,b; scanf("%d%d",&a,&b); printf("%d\n",gcd(a,b)); return 0; }
递归化简:
/* 辗转相除法 递归化简 */ #include<iostream> #include<stdio.h> using namespace std; int gcd(int a,int b){ return b==0?a:gcd(b,a%b); } int main(){ int a,b; scanf("%d%d",&a,&b); printf("%d\n",gcd(a,b)); return 0; }
ps:a,b的最大公约数记为(a,b),
a,b的最小公倍数记为[a,b],
它们的关系是:(a,b)*[a,b]=a*b。
3.进制转换
1.10进制转m进制
/* 10进制转m进制 */ #include<iostream> #include<string> using namespace std; int main() { int n,m; string ans; char num[16]= {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; cin>>n>>m; while (n) { ans=num[n%m]+ans; n=n/m; } cout<<ans; return 0; }
2.m进制转10进制
/* m进制转10进制 */ #include<iostream> #include<cstring> #include<cmath> using namespace std; int main() { int m,ans=0; char n[9],num[16]= {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; cin>>n>>m; for (int i=0; i<=strlen(n)-1; i++) for (int j=0; j<=16; j++) if (n[i]==num[j]) { ans+=j*pow(m,strlen(n)-i-1); break; } cout<<ans; return 0; }
4.质因数分解
c.质因数分解
/* 质因数分解 */ #include<iostream> #include<stdio.h> #include<math.h> using namespace std; void pf(int n){ int i,k; for(i=2,k=sqrt(n);i<=k;++i){ if(n%i==0){ printf("%d ",i); n=n/i; --i;//遇到++i复位,可以分解出相同的质因子 k=sqrt(n);//循环条件不直接写i<=sqrt(n);是因为这样可以避免重复开跟方 } } printf("%d\n",n); } int main(){ int n; scanf("%d",&n); pf(n); return 0; }
c2.质因数分解
/* 质因数分解 */ #include<iostream> #include<stdio.h> #include<math.h> using namespace std; const int MAXN=1024; int factors[MAXN][2];//[0]存质因子,[1]存个数 int factCnt;//不同的质因子总个数 void getFactors(int n){ int i,k; factCnt=0; for(i=2,k=sqrt(n);i<=k;++i){ if(n%i==0){ factors[factCnt][0]=i; factors[factCnt][1]=1; n=n/i; while(n%i==0){ ++factors[factCnt][1]; n=n/i; } ++factCnt; k=sqrt(n);//循环条件不直接写i<=sqrt(n);是因为这样可以避免重复开跟方 } } if(n>1){ factors[factCnt][0]=n; factors[factCnt][1]=1; ++factCnt; } } int main(){ int n; while(~scanf("%d",&n)){ getFactors(n); printf("不同的质因子总个数:%d\n",factCnt); int i,j; for(i=0;i<factCnt;++i){ for(j=0;j<factors[i][1];++j){ printf("%d ",factors[i][0]); } } printf("\n"); } return 0; }
kb2.2素数筛选和合数分解
/* 素数筛选和合数分解 */ #include<iostream> #include<stdio.h> #include<string.h> using namespace std; //素数筛选和合数分解 const int MAXN=10000; int prime[MAXN+1]; void getPrime(){ memset(prime,0,sizeof(prime)); for(int i=2;i<=MAXN;i++){ if(!prime[i])prime[++prime[0]]=i; for(int j=1;j<=prime[0]&&prime[j]<=MAXN/i;j++){ prime[prime[j]*i]=1; if(i%prime[j]==0)break; } } } long long factor[100][2]; int fatCnt; int getFactors(long long x){ fatCnt=0; long long tmp=x; for(int i=1;prime[i]<=tmp/prime[i];i++){ factor[fatCnt][1]=0; if(tmp%prime[i]==0){ factor[fatCnt][0]=prime[i]; while(tmp%prime[i]==0){ factor[fatCnt][1]++; tmp/=prime[i]; } fatCnt++; } } if(tmp!=1){ factor[fatCnt][0]=tmp; factor[fatCnt][1]=1; fatCnt++; } return fatCnt; } int main(){ getPrime(); getFactors(12);//12=2*2*3; for(int i=0;i<fatCnt;i++) for(int j=0;j<factor[i][1];j++) printf("%d ",factor[i][0]); return 0; }
5.欧拉函数
kb2.7.1分解质因数求欧拉函数
/* 分解质因数求欧拉函数 */ #include<iostream> #include<stdio.h> #include<string.h> using namespace std; //素数筛选和合数分解 const int MAXN=10000; int prime[MAXN+1]; void getPrime(){ memset(prime,0,sizeof(prime)); for(int i=2;i<=MAXN;i++){ if(!prime[i])prime[++prime[0]]=i; for(int j=1;j<=prime[0]&&prime[j]<=MAXN/i;j++){ prime[prime[j]*i]=1; if(i%prime[j]==0)break; } } } long long factor[100][2]; int fatCnt; int getFactors(long long x){ fatCnt=0; long long tmp=x; for(int i=1;prime[i]<=tmp/prime[i];i++){ factor[fatCnt][1]=0; if(tmp%prime[i]==0){ factor[fatCnt][0]=prime[i]; while(tmp%prime[i]==0){ factor[fatCnt][1]++; tmp/=prime[i]; } fatCnt++; } } if(tmp!=1){ factor[fatCnt][0]=tmp; factor[fatCnt][1]=1; fatCnt++; } return fatCnt; } int main(){ getPrime(); getFactors(8);//8=2*2*2; for(int i=0;i<fatCnt;i++) for(int j=0;j<factor[i][1];j++) printf("%d ",factor[i][0]); printf("\n"); int ret=8;//互质的数有1,3,5,7 for(int i=0;i<fatCnt;i++) ret=ret/factor[i][0]*(factor[i][0]-1); printf("%d\n",ret); return 0; }
kb2.7.2筛法欧拉函数
/* 筛法欧拉函数 */ #include<iostream> #include<stdio.h> #include<string.h> using namespace std; int euler[3000001]; void getEuler(){ memset(euler,0,sizeof(euler)); euler[1]=1; for(int i=2;i<=3000000;i++) if(!euler[i]) for(int j=i;j<=3000000;j+=i){ if(!euler[j]) euler[j]=j; euler[j]=euler[j]/i*(i-1); } } int main(){ getEuler(); printf("%d\n",euler[8]);//互质的数有1,3,5,7 return 0; }
kb2.7.3求单个数的欧拉函数
/* 求单个数的欧拉函数 */ #include<iostream> #include<stdio.h> using namespace std; long long euler(long long n){ long long ans=n; for(int i=2;i*i<=n;i++){ if(n%i==0){ ans-=ans/i; while(n%i==0) n/=i; } } if(n>1)ans-=ans/n; return ans; } int main(){ int e=euler(8);//互质的数有1,3,5,7 printf("%d\n",e); return 0; }
kb2.7.4线性筛(同时得到欧拉函数和素数表)
/* 线性筛(同时得到欧拉函数和素数表) */ #include<iostream> #include<stdio.h> #include<string.h> using namespace std; const int MAXN=10000000; bool check[MAXN+10]; int phi[MAXN+10]; int prime[MAXN+10]; int tot;//素数的个数 void phi_and_prime_table(int N){ memset(check,false,sizeof(check)); phi[1]=1; tot=0; for(int i=2;i<=N;i++){ if(!check[i]){ prime[tot++]=i; phi[i]=i-1; } for(int j=0;j<tot;j++){ if(i*prime[j]>N)break; check[i*prime[j]]=true; if(i%prime[j]==0){ phi[i*prime[j]]=phi[i]*prime[j]; break; } else{ phi[i*prime[j]]=phi[i]*(prime[j]-1); } } } } int main(){ phi_and_prime_table(100); for(int i=0;i<tot;i++) printf("%d ",prime[i]); printf("\n"); printf("%d\n",phi[8]);//互质的数有1,3,5,7 return 0; }
6.欧几里德、扩展欧几里德
一、欧几里德算法:即辗转相除法,用于求两个整数a,b的最大公约数
见:最大公约数模板
二、扩展欧几里德算法:对于不完全为0的非负整数a,b,gcd(a,b)表示a,b的最大公约数,必然存在整数对x,y,使得gcd(a,b)=ax+by。
kb2.3扩展欧几里德算法(求ax+by=gcd的解以及逆元)
/* 扩展欧几里德算法(求ax+by=gcd的解以及逆元) */ #include<iostream> #include<stdio.h> using namespace std; //返回d=gcd(a,b);和对应于等式ax+by=d中的x,y long long extend_gcd(long long a,long long b,long long &x,long long &y){ if(a==0&&b==0)return -1;//无最大公约数 if(b==0){x=1;y=0;return a;} long long d=extend_gcd(b,a%b,y,x); y-=a/b*x; return d; } //求逆元 //ax=1(mod n) long long mod_reverse(long long a,long long n){ long long x,y; long long d=extend_gcd(a,n,x,y); if(d==1)return (x%n+n)%n; else return -1; } int main(){ long long a,b,x,y; scanf("%lld%lld",&a,&b); long long d=extend_gcd(a,b,x,y); printf("%lld x=%lld y=%lld\n",d,x,y); return 0; }
7.逆元
kb2.4.1扩展欧几里德法
/* 求逆元 扩展欧几里德法 */ #include<iostream> #include<stdio.h> using namespace std; //返回d=gcd(a,b);和对应于等式ax+by=d中的x,y long long extend_gcd(long long a,long long b,long long &x,long long &y){ if(a==0&&b==0)return -1;//无最大公约数 if(b==0){x=1;y=0;return a;} long long d=extend_gcd(b,a%b,y,x); y-=a/b*x; return d; } //求逆元 //ax=1(mod n) long long mod_reverse(long long a,long long n){ long long x,y; long long d=extend_gcd(a,n,x,y); if(d==1)return (x%n+n)%n; else return -1; } int main(){ long long a,n; scanf("%lld%lld",&a,&n); printf("%lld\n",mod_reverse(a,n)); return 0; }
kb2.4.1简洁写法
注意:这个只能求a<m的情况,而且必须保证a和m互质
/* 求逆元 简洁写法 */ #include<iostream> #include<stdio.h> using namespace std; //求ax=1(mod m)的x值,就是逆元(0<a<m) long long inv(long long a,long long m){ if(a==1)return 1; return inv(m%a,m)*(m-m/a)%m; } int main(){ long long a,m; scanf("%lld%lld",&a,&m); printf("%lld\n",inv(a,m)); return 0; }
kb2.4.3利用欧拉函数
mod为素数,而且a和m互质
/* 求逆元 利用欧拉函数 */ #include<iostream> #include<stdio.h> #include<math.h> using namespace std; long long inv(long long a,long long mod){//为素数mod //return pow_m(a,mod-2,mod); return int(pow(a,mod-2))%mod; } int main(){ long long a,mod; scanf("%lld%lld",&a,&mod); printf("%lld\n",inv(a,mod)); return 0; }
8.常规求幂、二分求幂、快速求幂
HDU 2035 人见人爱A^B(二分求幂,快速求幂)
题意:求A的B次方的后三位数字
思路1:常规求幂,直接取余求解
代码:
/* 常规求幂 */ #include<iostream> #include<cstdio> using namespace std; int main(){ int a,b; int ans; while(~scanf("%d%d",&a,&b)){ if(a==0&&b==0) break; a=a%1000;//底数取余 ans=1; while(b--){ ans=(ans*a)%1000;//结果取余 } printf("%d\n",ans); } return 0; }
思路2:二分求幂(一般)
代码:
/* 二分求幂 */ #include<iostream> #include<cstdio> using namespace std; int main(){ int a,b; int ans; while(~scanf("%d%d",&a,&b)){ if(a==0&&b==0) break; a=a%1000;//底数取余 ans=1; while(b>0){//b==0时,所有的因子都已经相乘,循环结束。 if(b%2==1)//1.奇数时,多出来的一项提前放到ans里 2.b==1时,完成结果和底数的最后一次相乘 ans=(ans*a)%1000;//结果取余 a=(a*a)%1000;//二分操作 b=b/2;//1.二分 2.b==1时,b/2=0,作为结束循环的条件 } printf("%d\n",ans); } return 0; }
思路3:快速求幂(位操作)
Hint: 这不就是二分求幂么! 只不过改动了两个位操作。。。
b&1 可以判断是否为奇数,相当于 b%2==1
b=b>>1 表示b的二进制数向右移一位,相当于 b=b/2;
代码:
/* 快速求幂 */ #include<iostream> #include<cstdio> using namespace std; int main(){ int a,b; int ans; while(~scanf("%d%d",&a,&b)){ if(a==0&&b==0) break; a=a%1000; ans=1; while(b>0){ if(b&1)//判断是否为奇数,相当于 if(b%2==1) ans=(ans*a)%1000; a=(a*a)%1000; b=b>>1;//二进制向右移一位,相当于 b=b/2; } printf("%d\n",ans); } return 0; }
9.矩阵快速幂
/* 矩阵快速幂 */ #include<iostream> #include<stdio.h> #include<string.h> using namespace std; #define N 2//N*N的矩阵 const int MOD=1e9+7;// struct Matrix{ int mat[N][N]; }; Matrix mul(Matrix a,Matrix b){ Matrix ret; int i,j,k; for(i=0;i<N;++i){ for(j=0;j<N;++j){ ret.mat[i][j]=0; for(k=0;k<N;++k){ ret.mat[i][j]+=a.mat[i][k]*b.mat[k][j]; ret.mat[i][j]%=MOD; } } } return ret; } Matrix pow_matrix(Matrix a,int n){ Matrix ret; memset(ret.mat,0,sizeof(ret.mat)); int i; for(i=0;i<N;++i){ ret.mat[i][i]=1; } Matrix temp=a; while(n){ if(n&1){ ret=mul(ret,temp); } temp=mul(temp,temp); n>>=1; } return ret; } int main(){ Matrix a; a.mat[0][0]=1,a.mat[0][1]=2; a.mat[1][0]=3,a.mat[1][1]=4; Matrix b; b=pow_matrix(a,2); printf("%d %d\n",b.mat[0][0],b.mat[0][1]); printf("%d %d\n",b.mat[1][0],b.mat[1][1]); return 0; }
10.二分法解一元三次方程
#include<iostream> #include<stdio.h> #include<math.h> using namespace std; /* 二分法解一元三次方程ax^3+bx^2+cx+d=0 方程必须是单调的才行吧?目测是这样 */ void dichotomy(int a,int b,int c,int d,double x1,double x2){//二分法求[x1,x2]之间的根 double f1,f2; f1=a*x1*x1*x1+b*x1*x1+c*x1+d; f2=a*x2*x2*x2+b*x2*x2+c*x2+d; if(f1*f2>0){ printf("无解\n"); return; } if(fabs(f1)<1e-8){ printf("%f\n",x1); return; } if(fabs(f2)<1e-8){ printf("%f\n",x2); return; } double x3,f3; do{ x3=(x1+x2)/2; f3=a*x3*x3*x3+b*x3*x3+c*x3+d; if(f1*f3<0){ x2=x3; f2=f3; } else if(f3*f2<0){ x1=x3; f1=f3; } else{//f3==0 printf("%f\n",x3); return; } }while(fabs(f3)>=1e-8); //abs是取绝对值后再取整,而fabs是取绝对值之后不做操作 printf("%f\n",x3); return; } int main(){ //求方程f=2x^3-4x^2+3x-6=0在区间[-10,10]的解 dichotomy(2,-4,3,-6,-10,10); return 0; }