zoukankan      html  css  js  c++  java
  • 【模板】【学习笔记】noip数学

    一、素数

    欧拉筛

    void prime(){
        check[1]=1;
        for(int i=2;i<=n;i++){
            if(!check[i])prim[++cnt]=i;//这个if语句后面没有大括号!! 
            for(int j=1;j<=cnt&&prim[j]*i<=n;j++){
                check[i*prim[j]]=true;
                if(i%prim[j]==0)break;
            }
        }
    }

    简单的素数判定

    bool check(int x){
        if(x<=1)return false;
        for(int i=2;i*i<=x;i++)
            if(x%i==0)return false;
        return true;
    }

    洛谷p1218搜索+素数判定

    二、欧几里得+扩展欧几里得

    欧几里得

    int gcd(int x,int y){
        return y==0?x:gcd(y,x%y);
    }

    多组gcd预处理

    #include<iostream>
    #include<cstdio>
    using namespace std;
    int n,m,g[100][100];
    int main(){
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            g[i][i]=i;g[i][0]=g[0][i]=i;
            for(int j=1;j<i;j++){
                g[j][i]=g[i][j]=g[j][i%j];
            }
        }
        return 0;
    } 

    扩展欧几里得 

    求逆元:当一个数与它的模数m互质时,那么它在模m意义下的逆元为

    这个数的m-2次方。

    void exgcd(int a,int b,int &x,int &y){
        if(b==0){
            x=1;y=0;
            return a;
        }
        int r=exgcd(b,a%b,x,y),t;
        t=x;x=y;y=t-a/b*y;
        return r;
    }
    gcd=exgcd(a,b,x,y);
    if(gcd!=1)printf("不存在
    ")
    while(x<=0)x+b/gcd;

    洛谷p2054

    洛谷p1516

    三、欧拉函数

    phi(n)为小于等于n且与n互质的数的个数。

    int get_phi(int x){
        int sum=x;
        if(x%2==0){
            while(x%2==0)x/=2;
            sum/=2;
        }
        for(int i=3;i*i<=x;i+=2){
            if(x%i==0){
                while(x%i==0)x/=i;
                sum=sum/i*(i-1);
            }
        }
        if(x>1)sum=sum/x*(x-1);
        return sum;
    }

    hzwer的

    int phi(int n)
    {
        int ans=n;
        for(int i=1;pri[i]<=sqrt(n);i++)
            if(n%pri[i]==0)
            {
                ans=(ans-ans/pri[i]);
                while(n%pri[i]==0)n/=pri[i];
            }
        if(n!=1)ans=(ans-ans/n);
        return ans%K;
    }
    int euler(int n){ //返回euler(n)   
         int res=n,a=n;  
         for(int i=2;i*i<=a;i++){  
             if(a%i==0){  
                 res=res/i*(i-1);//先进行除法是为了防止中间数据的溢出   
                 while(a%i==0) a/=i;  
             }  
         }  
         if(a>1) res=res/a*(a-1);  
         return res;  
    }  
      

    hdu2588

    四、卡特兰数

    不想写了....博客会陆续写几道题的....

    去分类里找吧。谢谢滋瓷(。・・)ノ

    五、中国剩余定理

    设m1,m2,m3,m4两两互素,则同余方程组
    x≡a1(m1)
    x≡a2(m2)
    x≡a3(m3)
    x≡a4(m4)
    ....
    x≡ak(mk)
    一定有解,x≡(a1*M1*M1^(-1)+a2*M2*M2^(-1)+....)
    其中M=m1*m2*...*mk,Mi=M/mi,Mi^(-1)是Mi在模mi意义下的逆元。
    普通的中国剩余定理要求所有mi互素,那么如果不互素呢?
    我们采用两两合并的思想,假设要合并如下两个方程
    x=a1+m1*x1
    x=a2+m2*x2
    那么得到
    a1+m1x1=a2+m2x2 => m1x1+m2x2=a2-a1
    再利用扩展欧几里得算法解出x1的最小正整数解,再带入
    x=a1+m1x1,得到x后合并为一个方程的结果过为
    y≡x(mod lcm(m1,m2))
    这样一直合并下去,最终可以求得同余方程的解。
    模板:互素的
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    using namespace std;
    
    int a[4],m[4];
    int p,e,i,d,t=1;
    
    void exgcd(int a,int b,int &x,int &y){
        if(b==0){
            x=1;
            y=0;
            return;
        }
        exgcd(b,a%b,x,y);
        int tmp=x;
        x=y;
        y=tmp-(a/b)*y;
    }
    
    int CRT(int a[],int m[],int n){
        int M=1,ans=0;
        for(int i=1;i<=n;i++)M*=m[i];
        for(int i=1;i<=n;i++){
            int x,y;
            int Mi=M/m[i];
            exgcd(Mi,m[i],x,y);
            ans=(ans+Mi*x*a[i])%M;
        }
        if(ans<0)ans+=M;
        return ans;
    }
    
    int main(){
        while(cin>>p>>e>>i>>d){
            if(p==-1&&e==-1&&i==-1&&d==-1)break;
            a[1]=p;a[2]=e;a[3]=i;
            m[1]=23;m[2]=28;m[3]=33;
            int ans=CRT(a,m,3);
            if(ans<=d)ans+=21252;
            printf("Case %d: the next triple peak occurs in %d days.
    ",t++,ans-d);
        }
        return 0;
    }

    不互素的

    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<iostream>
    #include<algorithm>
    #define N 5
    #define ll long long 
    using namespace std;
    ll n,m[N],a[N],m1,e;
    ll read()
    {
        ll x=0,f=1; char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
        return x*f;
    }
    ll exgcd(ll a,ll b,ll &x,ll &y)
    {
        if(b==0)
        {
            x=1,y=0;
            return a;
        }
        ll r=exgcd(b,a%b,x,y),tmp;
        tmp=x,x=y,y=tmp-a/b*y;
        return r;
    }
    ll crt()
    {
        ll a1=a[1],a2,m2,d,c;m1=m[1];
        for(ll i=2;i<=n;++i)
        {
            a2=a[i],m2=m[i];
            c=a2-a1;ll x=0,y=0;
            d=exgcd(m1,m2,x,y);
            if(c%d) return  -1;
            x=x*c/d;
            int mod=m2/d;
            x=(mod+x%mod)%mod;
            a1+=m1*x;m1*=mod;
        }
        return a1;
    }
    int main()
    {
    //    freopen("mod.in","r",stdin);
    //    freopen("mod.out","w",stdout);
        n=4;
        for(int i=1;i<=n;i++) 
         m[i]=read(),a[i]=read();
        printf("%lld
    ",crt());
        return 0;
    }
     

    六、斐波那契

    递推公式:f[i]=f[i-1]+f[i-2],f[1]=f[2]=1

    通项公式:

    矩阵乘法求斐波那契:

    A:(F[i1]F[i])B=(01)

                                   (11)

    两个矩阵乘一乘就好啦。具体

    重要定理:gcd(f[n],f[m])=f[gcd(n,m)]

    七、排列组合

    排列公式:

    组合数公式:

    递推法求组合数

        for(int i=0;i<=k;i++)
        {
            for(int j=0;j<=i;j++)
            {
                if(j==0) c[i][j]=1;
                else if(i==j) c[i][j]=1;
                else c[i][j]=(c[i-1][j]%M+c[i-1][j-1]%M)%M;
            }
        }

    如果是计算C(n,m)%p,p是个素数,那么n!/(m!*(n-m)!)=n!*(f[m]*f[n-m])^(p-2)

    f[m]为m的阶乘。

    Lucas定理:用于大组合数取模问题

    插板法:不想多说...来个例题吧...

    十、错排

    错排:考虑n个元素的一个排列,若每个元素都不在原来的位置,那么这个

    排列就叫做原来排列的一个错排。

    错排公式:f[i]=(f[i-1]+f[i-2])*(i-1)

    错排通项公式:f[n]=n!*[(-1)^2/2!+(-1)^3/3!+(-1)^4/4!+...+(-1)^n/n!]

    OpenJudge 9278

    十一、容斥原理

    容斥原理是一种重要的组合数学的方法,可以让你求解任意组的大小,或者

    计算复合事件的概率。

    要计算几个集合合并的大小,我们要先将单个集合计算出来,然后减去所有

    两个集合相交的部分,再加回所有三个集合相交的部分,再减去所有四个集合

    相交的部分。依此类推.....

    几个例题:

    (1)简单排列问题

    0--9组成的排列,要求第一个数字大于1,最后一个数小于8,共有几个排列。

    首先算出第一个元素小于等于1(有x种排列)或者最后一个元素大于等于8

    (有Y种排列),通过容斥原理写成:

    |X|+|Y|-|X∩Y|。经过计算可以写成:

    2*9!+2*9!-2*2*8! 就是所有不满足条件的情况,再用总排列10!减去就是答案了。

    (2)序列问题

    长度为n的由数字0,1,2组成的序列,要求每个数字至少出现1次,这样的序列有

    多少种?

    定义Ai为不出现数字i的序列数,那么通过容斥原理,我们得到该逆问题的结果为:

    可以发现

     每个Ai值都是2^n,而所有两两组合的Ai∩Aj都为1,最后三个集合的交集为0;

    其他没什么好说的,贴上几个题吧。

    bzoj1042

    bzoj2393

  • 相关阅读:
    TinySpider开源喽
    TinyXmlParser开源喽
    Tiny快速入门之控制层开发
    TinyDBRouter
    TinyIOC
    开源前要做好哪些准备工作?
    分布式锁的简单实现
    TinyDBCluster Vs routing4db
    HTML5基础(五)
    HTML5基础(四)
  • 原文地址:https://www.cnblogs.com/zzyh/p/7666159.html
Copyright © 2011-2022 走看看