zoukankan      html  css  js  c++  java
  • 【説明する】数論

    一、斐波那契数列:

    详细请见:http://www.cnblogs.com/zxqxwnngztxx/p/6772498.html

     1 #include<iostream>
     2 #include<cmath>
     3 using namespace std;
     4 int main()
     5 {
     6     double a,n,ans;
     7     cin>>n;
     8     //n--;  //(第一项是0时)
     9     a=sqrt(5);
    10     ans =(a/5) * (pow( (1+a)/2 ,n) - pow((1-a)/2 ,n));
    11     cout<<ans; 
    12     return 0; 
    13 }
    通项公式
     1 #include<iostream>
     2 #include<cmath>
     3 #include<cstdio>
     4 using namespace std;
     5 int a[10001];
     6 int main()
     7 {
     8     int n;
     9     a[1]=1;
    10     a[2]=1;
    11     scanf("%d",&n);
    12     for(int i=3;i<=n;i++)
    13     {
    14         a[i]=a[i-1]+a[i-2];
    15     }
    16     cout<<a[n];
    17     return 0;
    18 }
    递推算法
     1 #include<iostream>
     2 #include<cmath>
     3 #include<cstdio>
     4 using namespace std;
     5 int a[10001];
     6 int f(int n)
     7 {
     8     if(n==1||n==2)return 1;
     9     else return f(n-1)+f(n-2);
    10 }
    11 int main()
    12 {
    13     int n;
    14     a[1]=1;
    15     a[2]=1;
    16     scanf("%d",&n);
    17     printf("%d",f(n));
    18     return 0;
    19 }
    递归算法

    接下来就是一些很神的东西啦!(快速幂)

     1 #include<iostream>
     2 #include<cstring>
     3 
     4 using namespace std;
     5 
     6 void multi(int a[2][2],int b[2][2],int q)//前缀 
     7 {
     8     int c[2][2];
     9     memset(c,0,sizeof(c));//进行初始化清空,因为不只有一组数据,有t组 
    10     for(int i=0;i<2;i++)
    11         for(int j=0;j<2;j++)
    12             for(int k=0;k<2;k++)
    13                 c[i][j]=(c[i][j]+(a[i][k]*b[k][j])%q)%q;
    14     for(int i=0;i<2;i++)
    15         for(int j=0;j<2;j++)
    16             a[i][j]=c[i][j];
    17 }
    18 
    19 void fastpow(int n,int q)
    20 {
    21     int result[2][2]={1,0,1,0};
    22     int a[2][2]={1,1,1,0};
    23     while(n)//如果n不为0,一直做下面的循环 
    24     {
    25         if(n&1)//表明如果它是奇数 
    26           multi(result,a,q);
    27         multi(a,a,q);
    28         n>>=1;//位运算,相当于n/2 
    29     }
    30     int ans=result[0][1]%q;
    31     cout<<ans<<endl;
    32 }
    33 int main ()
    34 {
    35     int t;//给出(t)多组数据 
    36     int n,q;//第几项,模几 
    37     cin>>t;
    38     while(t--)
    39     {
    40         cin>>n>>q;
    41         n++;//因为斐波那契数列是从第0项开始的 
    42         fastpow(n,q);//快速幂 
    43     }
    44     return 0;
    45 }
    运用快速幂求解

    快速幂如果不理解的话,接下来会讲到啦~


    二、素数:

    详细请见http://www.cnblogs.com/zxqxwnngztxx/p/6735297.html

    可做洛谷3383来练手https://www.luogu.org/problem/show?pid=3383

    线性筛法求素数的代码:

    自我感觉1比较好用~而且会快好多!(这个顺序应该是按ms排序的吧)

    #include <iostream>
    #include <cstdio>
    #include <cmath>
    using namespace std;
    
    const int Maxn = 10000001;
    int cnt,prime[Maxn];
    bool notprime[Maxn];
    
    int main() {
        int n,t;
        scanf("%d%d",&n,&t);
        notprime[0]=notprime[1]=true;
        for(int i=2; i<=n; ++i) {
            if(!notprime[i])
                prime[++cnt]=i;
            for(int j=1; j<=cnt && i*prime[j]<=n; ++j) {
                notprime[i*prime[j]]=true;
                if(i%prime[j]==0)
                    break;
            }
        }
        while(t--) {
            int i;
            scanf("%d",&i);
            if(notprime[i])
                printf("No
    ");
            else
                printf("Yes
    ");
        }
        return 0;
    }
    线性筛1
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    
    using namespace std;
    
    const int MAXN=10000001;
    
    int vis[MAXN];
    
    int main()
    {
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i=2;i<=sqrt(n);i++)
        {
            if(vis[i]==0)
            {
                for(int j=i*i;j<=n;j=j+i)
                {
                    vis[j]=1;
                }
            }
        }
        vis[1]=1; 
        int a;
        for(int i=1;i<=m;i++)
        {
            scanf("%d",&a);
            if(vis[a]==0) printf("Yes
    ");
            else printf("No
    ");
        }
        return 0;
    }
    线性筛2
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    
    using namespace std;
    
    const int MAXN=10000001;
    
    int vis[MAXN];
    
    int main()
    {
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i=2;i<=sqrt(n+0.5);i++)
        {
            if(!vis[i])
            {
                for(int j=i<<1;j<=n;j+=i)
                {
                    vis[j]=1;
                }
            }
        }
        vis[1]=1;
        int a;
        for(int i=1;i<=m;i++)
        {
            scanf("%d",&a);
            if(vis[a]==0) printf("Yes
    ");
            else printf("No
    ");
        }
        return 0;
    }
    线性筛3

    三、(扩展)欧几里得算法(裴蜀定理):

    详细请见:http://www.cnblogs.com/zxqxwnngztxx/p/6741002.html

    codevs有道题(同余方程)可以去做做试试:http://codevs.cn/problem/1200/

     1 #include<iostream>
     2 using namespace std;
     3 int main()
     4 {
     5     int n,m,r;
     6     cin>>m>>n;
     7     r=m%n;
     8     while(r!=0)
     9     {
    10         m=n;
    11         n=r;
    12         r=m%n;
    13     }
    14     cout<<n;
    15 }
    欧几里得算法
     1 #include<iostream>
     2 #include<cstdio>
     3 #include<algorithm>
     4 
     5 using namespace std;
     6 
     7 long long exgcd(long long a,long long b,long long &x,long long &y)
     8 {
     9     if(b==0)
    10     {
    11         x=1;
    12         y=0;
    13         return a;
    14     }
    15     long long r=exgcd(b,a%b,x,y),t=x;
    16     x=y;y=t-y*(a/b);
    17     return r; 
    18 }
    19 
    20 int main()
    21 {
    22     long long a1,b1,x1,y1;
    23     cin>>a1>>b1;
    24     exgcd(a1,b1,x1,y1);
    25     while(x1<0) x1+=b1;
    26     cout<<x1;
    27     return 0;
    28 } 
    扩展欧几里得算法

     四、求二元一次不定方程

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cmath>
     4 
     5 using namespace std;
     6 
     7 int x,y;
     8 
     9 int gcd(int a,int b)//求最大公约数
    10 {
    11     if(b==0)
    12     return a;
    13     else 
    14     return gcd(b,a%b);
    15 }
    16 
    17 int exgcd(int a,int b,int &x,int &y)//扩展欧几里得
    18 {
    19     if(b==0)
    20     {
    21         x=1;
    22         y=0;
    23         return a;
    24     }
    25     int r=exgcd(b,a%b,x,y);
    26     int temp=x;
    27     x=y;
    28     y=temp-(a/b)*y;
    29     return r;
    30 }
    31 int main()
    32 {
    33     int a,b,c;
    34     scanf("%d%d%d",&a,&b,&c);
    35     int y=gcd(a,b);
    36     if(c%y!=0)//判断是否有解,如果无解,输出“-1”,代表无法找到
    37     {
    38         printf("-1");
    39         return 0;
    40     }
    41     else exgcd(a,b,x,y);
    42     while(x<0)
    43     {
    44         x=x+b;
    45         y=y+b;
    46     }
    47     x*=c;
    48     printf("%d %d",x,y);
    49     return 0;
    50 }
    求二元一次不定方程

     五、快速幂

    详细请见:http://www.cnblogs.com/zxqxwnngztxx/p/6759223.html

    #include<iostream>
    #include<cmath>
    #include<cstdio>  
    #define LL long long
    
    using namespace std;
    
    LL b,p,k;
    
    LL fastpow(LL a,LL b)
    {
        LL r=1;
        LL base=a;
        while(b!=0)
        {
            if(b%2!=0)//奇次幂 
            r=r*base;
            base=base*base;
            b=b/2;
        }
        return r;
    }
    
    LL fff(LL n,LL m)
    {
        if(m == 0) return 1;
    
        LL t = fff(n,m /2);
    
        t = 1LL * t * t % k;
        if(m&1) t = 1LL * t * n % k;
    
        return t;  
    }
    
    LL mod_exp(LL a, LL b, LL c)        //快速幂取余a^b%c
    {
        LL res,t;
        res=1%c; 
        t=a%c;
        while(b)
        {
            if(b&1)
            {
                res=res*t%c;
            }
            t=t*t%c;
            b>>=1;//就等价于b/2(位运算) 
        }
        return res;
    }
    
    int main()
    {
        scanf("%lld%lld%lld",&b,&p,&k);
        LL tmpb=b;
        b%=k;//防止b太大 
          /* start 快速幂求得b^p */
        cout<<tmpb<<"^"<<p<<"="<<fastpow(b,p)<<endl;
          /* end 快速幂求得b^p */
    
          /* start 快速幂求得b^p%k */
        cout<<tmpb<<"^"<<p<<" mod "<<k<<"="<<mod_exp(b,p,k)<<endl;
              /* 方法一 end */
    
        cout<<tmpb<<"^"<<p<<" mod "<<k<<"="<<fff(b,p)<<endl;
              /* 方法二 end */
          /* end 快速幂求得b^p%k */
        return 0;
    }
    快速幂

    六、费马小定理

    详细请见:http://www.cnblogs.com/zxqxwnngztxx/p/6744377.html

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<cstdlib>
     5 #include<ctime>
     6 #define ll long long int//能够直接使用long long 
     7 
     8 using namespace std;
     9 
    10 ll n;
    11 ll pd[14]={10,35,77,535,71497,2,3,5,7,11,3161};
    12 ll fastmul(ll a,ll b)
    13 {
    14     ll r=0;
    15     ll base=a;
    16     while(b!=0)
    17     {
    18         if(b%2!=0)
    19         {
    20             b--;
    21             r=(r+base)%n;
    22         }
    23         b=b/2;
    24         base=(base+base)%n;
    25     }
    26     return r%n;
    27 }
    28 ll fastpow(ll a,ll b)
    29 {
    30     ll r=1;
    31     ll base=a;
    32     while(b!=0)
    33     {
    34         if(b%2!=0)
    35         r=fastmul(r,base)%n;
    36         base=fastmul(base,base)%n;
    37         b=b/2;
    38     }
    39     return r%n;
    40 }
    41 ll check(ll n)
    42 {
    43     if(n==2) return 1;
    44     if(n<2&&(n%2==0)) return 0;
    45     for(ll i=0;i<11;i++)
    46     {
    47         ll x=pd[i];//进行特判 
    48         if(x%n==0)
    49         continue;//继续往下判断循环条件执行语句
    50         ll ans=fastpow(x,n-1)%n;
    51         if(ans!=1)
    52         return 0;
    53     }
    54     return 1;
    55 }
    56 int main()
    57 {
    58     //srand(time(0));
    59     //scanf("%lld",&n);
    60     cin>>n;
    61     for(int i=1;i<=n;i++)
    62     {
    63         if(check(i)) printf("%d
    ",i);
    64     }
    65     return 0;
    66 }
    费马小定理

     七、威尔逊定理

    详细请见:http://www.cnblogs.com/zxqxwnngztxx/p/6769677.html

    ps:轻易不要用~~~

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio> 
     4 #include<cmath>
     5 
     6 using namespace std;
     7 
     8 long long int f(int p)
     9 {
    10     if(p==0)
    11     return 1;
    12     else return p*f(p-1);
    13 }
    14 int main()
    15 {
    16     int n;
    17     scanf("%d",&n);
    18     long long int ans=f(n-1);
    19     if(ans%n==n-1)
    20     printf("YES");
    21     else 
    22     printf("NO");
    23     return 0;
    24 }
    威尔逊定理

     八、Catalan数

    前一百:http://www.cnblogs.com/zxqxwnngztxx/p/6628239.html

     1 #include<iostream>
     2 
     3 using namespace std;
     4 
     5 long long int f[1001];
     6 
     7 int main()
     8 {
     9     int n;
    10     f[2]=1;
    11     f[3]=1;
    12     cin>>n;
    13     n=n+2;
    14     for(int i=4;i<=n;i++)
    15     {
    16         for(int j=2;j<=n-1;j++)
    17         {
    18             f[i]=f[j]*f[i-j+1]+f[i];
    19         }
    20     }
    21     cout<<f[n];
    22     return 0;
    23 }
    Catalan数

     九、高精度

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <string>
    using namespace std;
    
    const int M = 500;
    char a1[M],b1[M];
    int lena,lenb,lenc,x;
    int a[M],b[M],c[2*M];
    bool ok=false; //全局变量,判断是否需要交换a1与b1
    //add, subtract, multiply and divide
    
    void emm() { //初始化
        memset(a,0,sizeof(a));
        memset(b,0,sizeof(b));
        memset(c,0,sizeof(c));
    }
    
    void change() { //进行转化
        lena=strlen(a1); lenb=strlen(b1);
        for(int i=0; i<lena; ++i) a[lena-i]=(a1[i]-'0');   //转化为数字(逆序)
        for(int i=0; i<lenb; ++i) b[lenb-i]=(b1[i]-'0');
    }
    
    void print() {
        for(int i=lenc; i>=1; i--) printf("%d",c[i]);
        printf("
    ");
    }
    
    void add() { //
        printf("add:
    ");
        emm(); change();
    
        lenc=1,x=0;
        while(lenc<=lena||lenc<=lenb) {
            c[lenc]=a[lenc]+b[lenc]+x;
            x=c[lenc]/10;
            c[lenc]%=10;
            lenc++;
        }
        c[lenc]=x; //可能产生进位
        if(!c[lenc] && lenc>1) lenc--; //(也可能并没有产生进位)去除前导'0'
        print();
    }
    
    void subtract() { //
        printf("subtract:
    ");
        emm(); change();
    
        bool fu=false; //判断是否需要输出负号
        if(lena<lenb || (lena==lenb && strcmp(a1,b1)<0)) { //比较哪个数更加大一些
            swap(a1,b1);//小数减去大数一定为负数
            fu=true;
        }
    
        change(); //可能进行了位置的变化,此时进行更新len的长度
        lenc=1;
        while(lenc<=lena) {
            if (a[lenc]<b[lenc]) { //如果较大的那位数的当前位数减去较小的那位数的当前位数不够减
                a[lenc]+=10; //进行借位
                a[lenc+1]--; //对应的下一位高位进行减1 (数学知识...)
            }
            c[lenc]=a[lenc]-b[lenc]; //进行计算
            lenc++;
        }
        while(!c[lenc] && lenc>1) lenc--; //去除前导'0'
        if(fu) {
            printf("-");
            ok=true; //判断a1与b1是否发生变化
        }
        print();
    }
    
    void multiply() { //
        printf("multiply:
    ");
        emm();
        if(ok) swap(a1,b1);
        change();
    
        lenc=1,x=0;
        for(int i=1; i<=lena; i++) {
            x=0; //存放进位
            for(int j=1; j<=lenb; j++) {
                c[i+j-1]=a[i]*b[j]+x+c[i+j-1]; //当前乘积+上次乘积进位+原数
                x=c[i+j-1]/10;
                c[i+j-1]%=10;
            }
            c[i+lenb]=x; //进行进位操作
        }
        lenc=lena+lenb;
        while(c[lenc]==0 && lenc>1) lenc--; //删除前导零
        print();
    }
    
    void divide() { //除 (Ps:高精除以低精(整除))
        printf("divide:
    ");
        emm();
        x=0;
        int dis;
    
        printf("Please enter the divisor:
    ");
        scanf("%d",&dis);
        int len=strlen(a1);
    
        for(int i=0; i<len; ++i) a[i+1]=a1[i]-'0';
        for(int i=1; i<=len; i++) {
            c[i]=(x*10+a[i])/dis;
            x=(x*10+a[i])%dis;
        }
        lenc=1;
    
        while(c[lenc]==0 && lenc<lena) lenc++; //删除前导零
        for(int i=lenc; i<=lena; i++) printf("%d",c[i]);
        printf("
    ");
    }
    
    int main() {
        scanf("%s%s",a1,b1); //此处一定不要加'&'符!!!
    
        add();
        subtract();
        multiply();
        divide(); //默认a1是被除数
    
        printf("End.");
        return 0;
    }
    高精度

    update at [2017-11-06]

    //参考自Candy?
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    using namespace std;
    
    const int Mod = 10;
    struct Big {
        int a[520],n;
        int& operator [](int x) {return a[x];}
        Big() : n(0) {memset(a,0,sizeof(a));}
        void ini(int x) {a[++n]=x;}
    };
    
    Big operator * (Big a,Big b) {
        Big c;
        for(int i=1; i<=a.n; i++) {
            int q=0;
            for(int j=1; j<=b.n; j++)
                q+=c[i+j-1]+a[i]*b[j],c[i+j-1]=q%Mod,q/=Mod;
            c[i+b.n]=q;
        }
        c.n=a.n+b.n;
        while(c.n>1 && c[c.n]==0) c.n--;
        return c;
    }
    
    Big operator * (Big a,int b) {
        int q=0;
        for(int i=1; i<=a.n; i++)
            q+=a[i]*b,a[i]=q%Mod,q/=Mod;
        while(q) a[++a.n]=q%10,q/=10;
        return a;
    }
    
    Big operator + (Big a,Big b) {
        int q=0,n=max(a.n,b.n);
        for(int i=1; i<=n; i++) {
            q+= i<=a.n ? a[i] : 0;
            q+= i<=b.n ? b[i] : 0;
            a[i]=q%Mod,q/=Mod; 
        }
        a.n=n;
        if(q) a[++a.n]=q;
        return a;
    }
    
    Big operator - (Big a,Big b) {
        for(int i=1; i<=b.n; i++) {
            if(a[i]<b[i]) a[i]+=Mod,a[i+1]--;
            a[i]-=b[i];
        }
        int q=b.n+1;
        while(a[q]<0) a[q]+=Mod,a[++q]--;
        while(a.n>1 && a[a.n]==0) a.n--;
        return a;
    }
    
    void Print(Big &a) {
        for(int i=a.n; i>=1; i--) printf("%d",a[i]);
    }
    
    string s1,s2;
    int main() {
        cin>>s1>>s2; 
        int len1=s1.length(),len2=s2.length();
        Big a,b,c;
        for(int i=len1-1; i>=0; i--) a.ini(s1[i]-'0');
        for(int i=len2-1; i>=0; i--) b.ini(s2[i]-'0');
        //c=...;
        c=a+b;
        Print(c);
        return 0;
    }
    View Code

     十、逆元

    详细请见:http://www.cnblogs.com/zxqxwnngztxx/p/6880386.html

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    
    
    using namespace std;
    int a,b,m;
    int x,y;
    
    int 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),tmp;
        tmp=x,x=y;
        y=tmp-a/b*y;
        return r;
    }
    
    int fastpow(int a,int p)
    {
        int bb=a;int ans=1;
        while(p!=0)
        {
            if(p%2==1)ans=ans*bb;
            bb=bb*bb;
            p=p/2;
        }
        return ans;
    }
    
    int main()
    {
        scanf("%d%d%d",&a,&b,&m);
        for(int i=1;i<=sqrt(m);i++)
        {
            if(m%i==0)
            {
                int ans=exgcd(b,m,x,y);
                printf("%d",(a*ans)%m);
                return 0;    
            }
        }
        printf("%d",fastpow(b,m-2));
    }
    逆元

    十一、BSGS!

    详细请见:http://www.cnblogs.com/zxqxwnngztxx/p/6880136.html

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<map>
    #include<cmath>
    
    using namespace std;
    typedef long long LL;
    
    LL a,b,c;
    map<LL,LL> mp;
    
    LL qsm(LL m)
    {
        LL n = a;
    
        if(m == 0) return 1;
    
        LL t = qsm(m/2);
    
        t = 1LL*t*t%c;
        if(m&1) t = 1LL*t*n%c;
    
        return t;
    }
    
    int main()
    {
        //a^im=b*a^j(mod c)
        while (scanf("%lld%lld%lld",&c,&a,&b)!=EOF)
        {
            mp.clear();   //清空 
            if (a%c==0)   //判断a,c 是否互质,因为c 是质数,所以直接判断是否整除即可
            {
                printf("no solution
    ");
                continue;
            }
            LL m=ceil(sqrt(c));
            LL ans;
            for (LL j=0; j<=m; j++)
            {
                if (j==0)
                {
                    //当j=0时,a^j=1, b*a^j=b
                    ans=b%c;
                    mp[ans]=j;
                    continue;
                }
                ans=(ans*a)%c;
                //括号里的ans指a^(j-1)*b,(a^(j-1)*b)*a=(a^j)*b
                mp[ans]=j;//在((a^j)*b)%c的位置记录下j
            }
            LL t=qsm(m);//t=a^m
            ans=1;
            bool p=false;
            for (LL i=1; i<=m; i++)
            {
                ans=(ans*t)%c;//括号里的ans指的是((a^m)^(i-1))*(a^m)=(a^m)^i=a^(im)
                if (mp[ans])
                {
                    LL t=i*m-mp[ans];//t=x,因为我们设的x=i*m-j
                    printf("%lld
    ",t);
                    p=true;
                    break;
                }
            }
            if (!p)
                printf("no solution
    ");
        }
    }
    BSGS!

    暂时的End.

    (不定时更.看我学到哪里咯?哈哈哈)

    如果运气好也是错,那我倒愿意错上加错!

    ❀❀❀❀❀❀❀❀❀❀❀❀❀❀❀❀❀❀❀❀❀

  • 相关阅读:
    排序算法-简单选择排序
    pygame模块的简介
    python设计模式之工厂模式
    一次完整的HTTP请求流程(当我们在浏览器输入一个URL后,发生了什么)
    HTTP协议,TCP、UDP协议
    Django rest framework框架中有哪些组件
    flask
    Flask上下文管理
    mac如何开启两个vmware虚拟机
    HTTP状态码
  • 原文地址:https://www.cnblogs.com/zxqxwnngztxx/p/6740950.html
Copyright © 2011-2022 走看看