【説明する】数論

一、斐波那契数列:

详细请见: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.

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

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

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

原文地址:https://www.cnblogs.com/zxqxwnngztxx/p/6740950.html