數學模版

一.數論部分


1.素數測試

#include <iostream>  
#include <cmath>  
#include <algorithm>  
#include <cstdlib>  
#include <cstdio>  
#include <map>  
using namespace std;  
#define Times 10  
typedef long long LL;  
map<LL,int>mp;  
LL random(LL n)  
{  
    return LL ((double)rand()/RAND_MAX*n+0.5);  
}  
//避免出現了相乘取餘前造成的溢出  
LL multi(LL a,LL b,LL mod)  
{  
    LL ans=0;  
    while(b)  
    {  
        if(b&1)  
        {  
            b--;  
            ans=(ans+a)%mod;  
        }  
        else  
        {  
            b/=2;  
            a=(a+a)%mod;  
        }  
    }  
    return ans;  
}  
LL Pow(LL a,LL b,LL mod)  
{  
    LL ans=1;  
    while(b)  
    {  
        if(b&1)  
        {  
            b--;  
            ans=multi(ans,a,mod);  
        }  
        else  
        {  
            b/=2;  
            a=multi(a,a,mod);  
        }  
    }  
    return ans;  
}  
// 二次探測找到一個不是x=1或者x=p-1的解就一定不是素數  
bool witness(LL a,LL n)  
{  
    LL d=n-1;  
    while(!(d&1))//冪是偶數時有探測的必要  
        d>>=1;  
    LL t=Pow(a,d,n);  
    while(d!=n-1 && t!=1 && t!=n-1)//如果存在一個非1或非p-1的解,就不是素數  
    {  
        t=multi(t,t,n);  
        d<<=1;  
    }  
    return t==n-1 || d&1 ;  
}  
bool miller_rabin(LL n)  
{  
    if(n==2)  
        return true;  
    if(n<2 || !(n&1))  
        return false;  
    for(int i=1;i<=Times;i++)  
    {  
        LL a=random(n-2)+1;  
        if(!witness(a,n))  
            return false;  
    }  
    return true;  
}  
LL gcd(LL a,LL b)  
{  
    if(b==0)  
        return a;  
    return gcd(b,a%b);  
}  
LL pollard_rho(LL n,int c)  
{  
    LL x,y,d,i=1,k=2;  
    x=random(n-2)+1;  
    y=x;  
    while(1)  
    {  
        i++;  
        x=(multi(x,x,n)+c)%n;  
        d=gcd(y-x,n);  
        if(1<d && d<n)  
            return d;  
        if(y==x)  
            return n;  
        if(i==k)  
        {  
            y=x;  
            k<<=1;  
        }  
    }  
}  
void find(LL n,LL c)  
{  
    if(n==1)  
        return ;  
    if(miller_rabin(n))  
    {  
        mp[n]++;  
        return ;  
    }  
    LL p=n;  
    while(p>=n)  
        p=pollard_rho(p,c--);  
    find(p,c);  
    find(n/p,c);  
}  


2.素數篩法等

分段篩素數:  
  
100W 差不多接近8W素數  
  
void make_prime()    
{    
    m.clear();    
    unsigned __int64 tmp;    
    memset(cnt,true,sizeof(cnt));    
    for(int i=1;i<=n_prime;i++)    
    {    
        tmp=l/num[i];    
        while(tmp*num[i]<l||tmp<=1)    
            tmp++;    
        for(unsigned __int64 j=tmp*num[i];j<=r;j+=num[i])    
        {    
            if(j>=l&&j<=r)    
                cnt[j-l]=0;    
        }    
    }    
    if(l==1)    
        cnt[0]=0;    
    for(unsigned __int64 i=0;i+l<=r;i++)    
        if(cnt[i]&&i+l<=r&&i>=0)    
            m[i+l]++;    
}


求因子和

void factor_sum()  
{  
    for(int i=1;i<=maxn;i++)  
        prime[i]=1;  
    for(int i=2;2*i<=maxn;i++)  
            for(int j=2*i;j<=maxn;j+=i)  
                prime[j]+=i;  
    prime[1]=0;  
}  
另外一種求法:  
(pn^(xn+1)-1)/(pn-1)的累乘


3.歐拉函數

phi[i]=i*(1-1/p1)*(1-1/p2)*(1-1/p3)...

單獨求歐拉值:  
long long euler(long long x)  
{  
    if(x==1)  
        return 0;  
    long long i,res=x;  
    for(i=2;i*i<=x;i++)  
        if(x%i==0)  
        {  
            res=res/i*(i-1);  
            while(x%i==0)  
                x/=i;  
        }  
    if(x>1)  
        res=res/x*(x-1);  
    return res;  
}  


遞推求歐拉值:  
void Phi()  
{  
    for(int i=1;i<=maxn;i++)  
        phi[i]=i;  
    for(int i=2;i<=maxn;i+=2)  
        phi[i]/=2;  
    for(int i=3;i<=maxn;i+=2)  
        if(phi[i]==i)  
            for(int j=i;j<=maxn;j+=i)  
                phi[j]=phi[j]/i*(i-1);  
}


歐拉公式的引伸:  
    小於或等於n的數中,與n互質的數的總和爲:φ(x) * x / 2。(n>1)


線性求歐拉值:  
const int maxn=1000001;  
long long euler[maxn];  
long long prime[maxn/3];  
bool isprime[maxn];  
void solve()  
{  
    int cnt=0;  
    memset(isprime,1,sizeof(isprime));  
    for(int i=2;i<maxn;i++)  
    {  
        if(isprime[i])  
        {  
            prime[++cnt]=i;  
            euler[i]=i-1;  
        }  
        for(int j=1;j<=cnt&&prime[j]*i<maxn;j++)  
        {  
            isprime[prime[j]*i]=0;  
            if(i%prime[j]!=0)  
                euler[i*prime[j]]=euler[i]*euler[prime[j]];  
            else  
            {  
                euler[i*prime[j]]=euler[i]*prime[j];  
                break;  
            }  
        }  
    }  
    euler[1]=0;  
}  


4.Lucas

對於組合數C(n,m)方便求出來的情況,直接求fac,然後用逆元解  
  
void init()  
{  
    fac[0]=1;  
    for(int i=1;i<=p;i++)  
        fac[i]=fac[i-1]*i%p;  
}  
long long C(long long n,long long m)  
{  
    if(n<m)  
        return 0;  
    long long ans=fac[n]*Pow(fac[n-m]*fac[m]%p,p-2,p)%p;  
    return ans;  
}  
  
不然的話,就只好一步一步逆元的求解組合數  
  
long long C(long long n,long long m)  
{  
    if(n<m)  
        return 0;  
    long long ans=1;  
    for(int i=1;i<=m;i++)  
       ans=(((n-m+i)%p)*Pow(i,p-2,p)%p)*ans%p;  
    return ans;  
}  
long long Lucas(long long n,long long m)  
{  
    if(m==0)  
        return 1;  
    return Lucas(n/p,m/p)*C(n%p,m%p)%p;  
}


二.矩陣

一類是具體題目具體 構造的,類型比較多,也有涉及到數的實部虛部,狀態什麼的,沒什麼好寫的。

這裏翻牆可以看到一篇比較好的資料和習題:http://zobayer.blogspot.com/2010/11/matrix-exponentiation.html

另一種就是對平面內點的變換了,具體看下圖:

                           轉自 matrix67

具體實現如下:(注意全部操作應爲,操作矩陣 * 目標矩陣)

#define PI acos(-1.0)    
struct Matrix    
{    
    double m[4][4];    
}E,matrix[10010];    
void init()    
{    
    for(int i=1;i<=3;i++)    
        for(int j=1;j<=3;j++)    
        {    
            if(i==j)    
                E.m[i][j]=1.0;    
            else    
                E.m[i][j]=0.0;    
        }    
}    
Matrix init_translation(double _x,double _y)    
{    
    Matrix ans=E;    
    ans.m[1][3]=_x;    
    ans.m[2][3]=_y;    
    return ans;    
}    
Matrix init_zoom(double l)    
{    
    Matrix ans=E;    
    ans.m[1][1]=l;    
    ans.m[2][2]=l;    
    return ans;    
}    
Matrix init_up_down()    
{    
    Matrix ans=E;    
    ans.m[2][2]=-1;    
    return ans;    
}    
Matrix init_left_right()    
{    
    Matrix ans=E;    
    ans.m[1][1]=-1;    
    return ans;    
}    
Matrix Multi(Matrix A,Matrix B)    
{    
    Matrix ans;    
    for(int i=1;i<=3;i++)    
        for(int j=1;j<=3;j++)    
        {    
            ans.m[i][j]=0;    
            for(int k=1;k<=3;k++)    
                ans.m[i][j]+=A.m[i][k]*B.m[k][j];    
        }    
    return ans;    
}    
Matrix init_rotate(double r)    
{    
    Matrix ans=E;    
    ans.m[1][1]=cos(r);    
    ans.m[1][2]=-sin(r);    
    ans.m[2][1]=sin(r);    
    ans.m[2][2]=cos(r);    
    return ans;    
}    
Matrix last(Matrix A,Matrix B)    
{    
    Matrix ans;    
    for(int i=1;i<=3;i++)    
        for(int j=1;j<=1;j++)    
        {    
            ans.m[i][j]=0;    
            for(int k=1;k<=3;k++)    
                ans.m[i][j]+=A.m[i][k]*B.m[k][j];    
        }    
    return ans;    
}



三.方程之類


擴展歐幾里得:

long long exgcd(long long a,long long b,long long &x,long long &y)  
{  
    if(b==0)  
    {  
        x=1;  
        y=0;  
        return a;  
    }  
    else  
    {  
        long long ans=exgcd(b,a%b,x,y);  
        long long t=x;  
        x=y;  
        y=t-a/b*y;  
        return ans;  
    }  
}  
//開始的時候對於方程 ax+by=c 可以方程兩邊同時除以gcd(a,b)   
//    c%gcd(a,b)!=0 時無解  
// 得到的解x0,y0實際上爲特解,通解是 x=x0+k*b/gcd(a,b) y=y0-k*a/gcd(a,b)  
//若是求x的最小值,首先要還原(因爲原方程解的是ax+by=1的解)x*=c,然後是x%=b...  
//求方程的r=gcd(a,b)個解:For(i=1...r) ans[i]=x0+(i-1)*b//這裏的b就是前面的b/gcd(a,b)

擴展歐幾里得求逆元:

求 (a/b)%mod   
  =((a%mod)*(b^-1%mod))%mod  
    
由exgcd可以得到  
    方程 b*b^-1 = 1(%mod)  
    即 b*b^-1+k*mod = 1  
  so  
    b^-1 = (x%mod+mod)%mod;  
      
特殊情況:  
    當b是質數時,由費馬小定理可知a^(p-1)=1(mod p)  
    so  
       a^-1 = a^(p-2) 

一元線性同餘方程組:

// 已知 n 和 x=a[i](mod b[i])  
  
//大體思路是兩兩運算,推出新的方程,然後運算  
//已知輸入的線性方程爲  
// x=a1(mod b1)  
// x=a2(mod b2)  
// ...  
// x=an(mod bn)  
//先看第一個 x-a1=b1y1  x-a2=b2y2  
// 聯立:b1y1-b2y2=a2-a1  
bool solve()  
{  
    a[0]=a[1],b[0]=b[1];  
    for(int i=2;i<=n;i++)  
    {  
        int a0=b[0];  
        int b0=b[i];  
        int c0=a[i]-a[0];  
        int x0,y0;  
        int r=gcd(a0,b0);  
        if(c0%r!=0)  
            return false;  
        else  
        {  
            a0/=r;  
            b0/=r;  
            c0/=r;  
            exgcd(a0,b0,x0,y0);  
            x0*=c0;  
            x0=(x0%b0+b0)%b0;  
            a[0]=b[0]*x0+a[0];  
            b[0]=b[0]*b0;  
        }  
    }  
    return true; // a[0]爲小於[b1,b2...bn]的非負整數解  
}

中國剩餘定理:  
int CRT(int r)  
{  
    long long M=1;  
    long long i,d,x0,y0,ans=0;  
    for(i=1;i<=r;i++)  
        M*=w[i];//好像很容易溢出的樣子,CRT弱爆了  
    for(i=1;i<=r;i++)  
    {  
        d=M/w[i];  
        exgcd(d,w[i],x0,y0);  
        ans=(ans+d*x0*a[i])%M;  
    }  
    while(ans<= 0)  
       ans+=M;  
    return ans;  
}  
//用w[]表示模數(兩兩互質),a[]表示餘數,返回值是以M爲模的解  

高次同餘方程:

// 已知 A^x=B(mod C)  
  
#include <iostream>    
#include <cstdio>    
#include <cmath>    
#define maxn 65535    
using namespace std;    
struct hash    
{    
    int a,b,next;    
}Hash[maxn*2];    
int flg[maxn+66];    
int top,idx;    
void ins(int a,int b)    
{    
    int k=b&maxn;    
    if(flg[k]!=idx)    
    {    
        flg[k]=idx;    
        Hash[k].next=-1;    
        Hash[k].a=a;    
        Hash[k].b=b;    
        return ;    
    }    
    while(Hash[k].next!=-1)    
    {    
        if(Hash[k].b==b)    
            return ;    
        k=Hash[k].next;    
    }    
    Hash[k].next=++top;    
    Hash[top].next=-1;    
    Hash[top].a=a;    
    Hash[top].b=b;    
}    
int find(int b)    
{    
    int k=b&maxn;    
    if(flg[k]!=idx)    
        return -1;    
    while(k!=-1)    
    {    
        if(Hash[k].b==b)    
            return Hash[k].a;    
        k=Hash[k].next;    
    }    
    return -1;    
}    
int gcd(int a,int b)    
{    
    return !b?a:gcd(b,a%b);    
}    
int exgcd(int a,int b,int &x,int &y)    
{    
    int t,ans;    
    if(!b)    
    {    
        x=1;    
        y=0;    
        return a;    
    }    
    ans=exgcd(b,a%b,x,y);    
    t=x;    
    x=y;    
    y=t-a/b*y;    
    return ans;    
}    
int Inval(int a,int b,int n)    
{    
    int x,y,e;    
    exgcd(a,n,x,y);    
    e=(long long)x*b%n;    
    return e<0?e+n:e;    
}    
int pow_mod(long long a,int b,int c)    
{    
    long long ans=1;    
    a%=c;    
    while(b)    
    {    
        if(b&1)    
        {    
            ans=ans*a%c;    
        }    
        a=a*a%c;    
        b>>=1;    
    }    
    return ans;    
}    
int  BabyStep(int A,int B,int C)    
{    
    top=maxn;    
    ++idx;    
    long long buf=1%C,D=buf,K;    
    int i,d=0,tmp;    
    for(i=0;i<=100;buf=buf*A%C,i++)    
        if(buf==B)    
            return i;    
    while((tmp=gcd(A,C))!=1)    
    {    
        if(B%tmp) return -1;    
        ++d;    
        C/=tmp;    
        B/=tmp;    
        D=D*A/tmp%C;    
    }    
    int M=(int)ceil(sqrt((double)C));    
    for(buf=1%C,i=0;i<=M;buf=buf*A%C,++i)    
        ins(i,buf);    
    for(i=0,K=pow_mod((long long)A,M,C);i<=M;D=D*K%C,++i)    
    {    
        tmp=Inval((int)D,B,C);    
        int w=find(tmp);    
        if(tmp>=0&&w!=-1)    
          return i*M+w+d;    
    }    
    return -1;    
}    
int main()    
{    
    int A,B,C;    
    while(scanf("%d%d%d",&A,&C,&B)!=EOF,A||B||C)    
    {    
        B%=C;    
        int tmp=BabyStep(A,B,C);    
        if(tmp<0)    
            printf("No Solution\n");    
        else    
            printf("%d\n",tmp);    
    }    
    return 0;    
}


佩爾方程:

已知方程 x^2 - d*y^2 = 1  
   
 可知迭代方程:  
     x(n) = x(n-1)*x1 + d*y(n-1)*y1  
     y(n) = x(n-1)*y1 + y(n-1)*x1  
       
 用矩陣快速冪求解:  
     |  x(n) |   =  | x1  dy1 |^(n-1) |  x1 |  
     |  y(n) |   =  | y1   x1 |       | y1 |


高斯模板  // czyuan大神

int equ,var;/// equ個方程,var個變量    
int a[maxn][maxn];    
int x[maxn];///解    
bool free_x[maxn];///不確定變元    
int free_num;    
void debug()    
{    
    for(int i=0;i<equ;i++)    
    {    
        for(int j=0;j<var+1;j++)    
            printf("%d ",a[i][j]);    
        printf("\n");    
    }    
    printf("\n");    
}    
int gcd(int a,int b)    
{    
    if(b==0)    
        return a;    
    return gcd(b,a%b);    
}    
int lcm(int a,int b)    
{    
    return a/gcd(a,b)*b;    
}    
/// -2表示浮點解 -1表示無解 0表示唯一解 大於0表示自由變元個數    
int gauss()    
{    
    int i,j,k;    
    int max_r;    
    int col=0;    
    int ta,tb;    
    int LCM;    
    int tmp;    
    int free_x_num;    
    int free_index;    
    for(k=0;k<equ&&col<var;k++,col++)    
    {    
        max_r=k;    
        for(i=k+1;i<equ;i++)    
        {    
            if(abs(a[i][col])>abs(a[max_r][col]))    
                max_r=i;    
        }    
        if(max_r!=k)    
        {    
            for(j=k;j<var+1;j++)    
                swap(a[k][j],a[max_r][j]);    
        }    
        if(a[k][col]==0)    
        {    
            k--;    
            continue;    
        }    
        for(i=k+1;i<equ;i++)    
        {    
            if(a[i][col]!=0)    
            {    
                LCM=lcm(abs(a[i][col]),abs(a[k][col]));    
                ta=LCM/abs(a[i][col]);    
                tb=LCM/abs(a[k][col]);    
                if(a[i][col]*a[k][col]<0)    
                    tb=-tb;    
                for(j=col;j<var+1;j++)    
                    a[i][j]=a[i][j]*ta-a[k][j]*tb;    
            }    
        }    
    }    
    for(i=k;i<equ;i++)    
        if(a[i][col]!=0)    
            return -1; /// 無解    
    if(k<var) /// 無窮解    
    {    
        for(i=k-1;i>=0;i--)    
        {    
            free_x_num=0;    
            for(j=0;j<var;j++)    
            {    
                if(a[i][j]!=0&&free_x[j])    
                {    
                    free_x_num++;    
                    free_index=j;    
                }    
            }    
            if(free_x_num>1)    
                continue;    
            tmp=a[i][var];    
            for(j=0;j<var;j++)    
            {    
                if(a[i][j]!=0&&j!=free_index)    
                    tmp-=a[i][j]*x[j];    
            }    
            x[free_index]=tmp/a[i][free_index];    
            free_x[free_index]=0;    
        }    
        return var-k;    
    }    
    for(i=var-1;i>=0;i--)    
    {    
        tmp=a[i][var];    
        for(j=i+1;j<var;j++)    
            if(a[i][j]!=0)    
                tmp-=a[i][j]*x[j];    
        if(tmp%a[i][i]!=0)    
            return -2;    
        x[i]=tmp/a[i][i];    
    }    
    return 0;    
}

java版的高斯消元(分數) hdu2449.java



四.不是很重要的東西


[1].n!的素因子分解中素數p的冪爲[n/p]+[n/p^2]+[n/p^3]+...

[2].C(2n,n)中素數p的冪爲([2n/p]-2[n/p])+([2n/p^2]+2[n/p^2])+...+([2n/p^t]-2[n/p^t])  
      t=[logp(2n)]

[3].梅森素數:  
Lucas-Lehmer判定法:(注意期間平方運算可能會溢出)  
對於第p個梅森數Mp=2^p-1,R1=4,對於k>=2,根據Rk=(R(k-1))^2-2(mod Mp)得到Rk序列,則Mp是素數,當且僅當R(p-1)=0(mod Mp)  
bool Lucas-Lehmer(int p)  
{  
    long long ans=1;// 開始寫的是 long long ans=(1<<p)  
    ans<<=p;//然後試出來,那個1是默認的int,必須改成 ans=((long long)1<<p);  
    ans--;    
    printf("%lld",ans);  
    long long R[65]={0,4};  
    for(int i=2;i<=p-1;i++)  
    {  
        long long tmp=multi(R[i-1],R[i-1],ans);  
        R[i]=(tmp-2)%ans;// multi寫一個a*b%m就好  
    }  
    if(p==2) //特判  
        return true;  
    else  
    {  
        if(R[p-1]==0)  
            return true;  
        return false;  
    }  
}

[4]畢達哥拉斯三元組  
x=m*m-n*n;   y=2*m*n;  z=m*m+n*n (m,n不同爲奇數和偶數)

[5]佩爾方程  
X^2 - dY^2 =1 令最小解爲X1,Y1  
Xn=Xn-1*X1+d*Yn-1*Y1  
Yn=Xn-1*Y1+Yn-1*X1

[6]迴文數個數  
求10^n範圍內迴文數的個數:  
if(n%2==0)           
   f(n)=2*(10^(n/2)-1);  
else  
   f(n)=11*10^((n-1)/2)-2;

[7]大數數字前n項  
可以對10取對數,得到的值減去floor部分,再將剩下的部分還原

[8]勒讓德兩平方數之和定理:R(N)=4*D1(N)-4*D3(N)  
D1(N)=(整除N 且滿足d=1(mod 4)的正約數d 的個數),  
D3(N)=(整除N 且滿足d=3(mod4)的正約數d 的個數)。

[9]指數循環節  
a^b mod c = a^(b%phi(c))%c (b>phi(c))


[10]Catalan數 C(2n,n)/(n+1)  
高精度樣例可以參照:hdu1131

[11] sigma(gcd(x,y))
sigma(gcd(i,n))=sigma(j*euler(n/j)+n/j*euler(j))  (n%j==0)

[12] 五邊形數定理  參照:http://zh.wikipedia.org/wiki/%E4%BA%94%E9%82%8A%E5%BD%A2%E6%95%B8%E5%AE%9A%E7%90%86



微積分啥的,遇到了,拿微積分表當模版吧

傅里葉變換,不會,這模版估計也不會用,跳過

莫比烏斯反演和polya計數等還得學,或者直接丟掉


其他遇到了,再學吧,再補充。




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章