数学

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;
}
View Code

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;
}
View Code

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;
}
View Code

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;
}
View Code

 

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;
}
View Code

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;
}
View Code

3.辗转相除法(欧几里德算法)

其中“a mod b”是指取 a ÷ b 的余数。
例如,123456 和 7890 的最大公因子是 6,这可由下列步骤看出:
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;
}
View Code

递归:

/*
辗转相除法
递归
*/
#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;
}
View Code

递归化简:

/*
辗转相除法
递归化简
*/
#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;
}
View Code

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;
}
View Code

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;
}
View Code

 

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;
}
View Code

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;
}
View Code

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;
}
View Code

 

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;
}
View Code

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;
}
View Code

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;
}
View Code

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;
}
View Code

 

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;
}
View Code

 

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;
}
View Code

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;
}
View Code

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;
}
View Code

 
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;
}
View Code

思路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;
}
View Code

思路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;
}
View Code

 

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;
}
View Code

 

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;
}
View Code

 

posted @ 2016-04-08 19:46  gongpixin  阅读(311)  评论(0编辑  收藏  举报