[模板]數學整合

數學整合:爲10天后的考試準備!ios

 

 

1.1:歐幾里得算法(位運算)c++

   目前接觸到的最快的求GCD的算法,並且不算太長,值得一記(雖然沒有什麼題目卡GCD吧。。。)git

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstdlib>
 4 #include<algorithm>
 5 #define man 10000000
 6 #define sc(x) scanf("%d",&x)
 7 using namespace std;
 8 int n,x,y;
 9 inline int gcd(int a,int b)
10 {
11     if(!a||!b)
12         return a^b;
13     int i=0,j=0;
14     while(!(a&1))
15         a>>=1,i++;
16     while(!(b&1))
17         b>>=1,j++;
18     while(a!=b)
19     {
20         if(a<b)
21             a^=b,b^=a,a^=b;
22         a-=b;
23         while(!(a&1))
24             a>>=1;
25         }
26     return a<<min(i,j);
27     }
28 int main()
29 {
30     for(;;)
31     {
32         sc(x);sc(y);
33         cout<<gcd(x,y)<<endl;
34         }
35     return 0;
36     }

 

1.2:普通版算法

  代碼簡潔,實用!函數

 

1 //只打出主要的部分:
2 
3 int gcd(int a,int b)
4 {   if(b==0) return a;
5      else return gcd(b,a%b);
6     }

 

 

 

2:擴展歐幾里得算法spa

   重點知識!必須牢記!還要知道各個變量的含義!.net

  擴展歐幾里得算法實質求的是   ax+by=c=k*gcd(a,b)code

  因此咱們求的是   ax+by=gcd(a,b)blog

  求出以後判斷    c%gcd(a,b)是否等於0ci

  若不能被整除,則表明無解;

  若ax+by=gcd(a,b)的解爲(x,y),ax+by=c的解(x,y)=(c/gcd(a,b)*x, c/gcd(a,b)*y)

 

 1 #include<bits/stdc++.h>
 2 #define man 110000
 3 #define sc(x) scanf("%lld",&x)
 4 #define LL long long
 5 using namespace std;
 6 LL a,b,k,x,y;
 7 LL exgcd(LL a,LL b,LL &x,LL &y)
 8 {
 9     if(b==0)
10     {
11         x=1;y=0;
12         return a;
13         }
14     else
15     {
16         LL ret=exgcd(b,a%b,x,y);
17         LL t=x;
18         x=y;
19         y=t-(a/b)*y;
20         return ret;
21         }
22     }
23 int main()
24 {
25     sc(a);sc(b);sc(k);
26     LL d=exgcd(a,b,x,y);
27     if(k%d!=0)
28         printf("No\n");
29     else 
30     {
31         x=x*(k/d);
32         y=(k-a*x)/b;
33         cout<<x<<" "<<y<<endl;
34         }
35     return 0;
36     }

 

3:快速冪

  這個實在沒什麼好講的了。。。

 1 #include<bits/stdc++.h>
 2 #define sc(x) scanf("%d",&x)
 3 using namespace std;
 4 int n,m;
 5 int p,ans=1;
 6 void bPow(int a,int b,int p)//Binary_Pow
 7 {    int base=a;
 8     while(b)
 9     {
10         if(b&1) ans=ans%p*base;
11         base=base*base%p;
12         b>>=1;
13         }
14     }
15 int main()
16 {
17     sc(n);sc(m);sc(p);
18     bPow(n,m,p);
19     cout<<ans<<endl;
20     return 0;
21     }

 

4:快速乘

  也沒什麼講的,就是把快速冪的乘號變成加號(效率不錯)

 1 //快速乘至關於乘法,例 3 5 10 =3*5%10
 2 #include<bits/stdc++.h>
 3 #define sc(x) scanf("%d",&x)
 4 using namespace std;
 5 int n,m;
 6 int p,ans=0;
 7 void bAdd(int a,int b,int p)
 8 {    int base=a;
 9     while(b)
10     {
11         if(b&1) ans=(ans+base)%p;
12         base=(base+base)%p;
13         b>>=1;
14         }
15     }
16 int main()
17 {
18     sc(n);sc(m);sc(p);
19     bAdd(n,m,p);
20     cout<<ans<<endl;
21     return 0;
22     }

 

5.乘法逆元    a*n ≡ 1(mod p)

  5.1當p爲素數時,咱們能夠直接使用費馬小定理操做:

  使用快速冪

#include<bits/stdc++.h>
using namespace std;
inline long long bpow(long long a,long long b,long long mod)
{    long long base=a,ans=1;
    while(b)
    {    if(b&1) ans=(ans*base)%mod;
        base=(base*base)%mod;
        b>>=1;
        }
    return ans;
    } 
void write(long long z)//快輸
{    char r[1001011];
    long long len=0;
    if(!z)
    {
        putchar(48);
        putchar('\n');
        return;
    }
    for(;z;z/=10)r[++len]=z%10;
    while(len)putchar(r[len--]+48);
    putchar('\n');
}
long long n,p;
int main()
{    scanf("%lld%lld",&n,&p);
    for(long long i=1;i<=n;i++)
    write(bpow(i,p-2,p));
    return 0;
    }

 

  5.2使用線性遞推式進行求解

  能夠參照 洛谷 P3811

#include<bits/stdc++.h>
using namespace std;
long long inv[3000010];
long long n,p;
int main()
{    scanf("%lld%lld",&n,&p);
    inv[1]=1;
    printf("1\n");
    for(int i=2;i<=n;i++)
        inv[i]=(p-(p/i))*inv[p%i]%p,printf("%lld\n",inv[i]);//需牢記遞推式
    return 0;
    }

  5.3使用歐幾里得算法進行求解

  實質求    ax+py=1    中的 x

 

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 using namespace std;
 5 int n,mod;
 6 inline int read()
 7 {
 8     char c=getchar();int  flag=1,x=0;
 9     while(c<'0'||c>'9')    {if(c=='-')    flag=-1;c=getchar();}
10     while(c>='0'&&c<='9')    x=x*10+c-48,c=getchar();    return x*flag;
11 }
12 int x,y;
13 int exgcd(int a,int b,int &x,int &y)
14 {
15     if(b==0)
16     {
17         x=1,y=0;
18         return a;
19     }
20     int r=exgcd(b,a%b,x,y);
21     int tmp=x;x=y;y=tmp-(a/b)*y;
22     return r;
23 }
24 int main()
25 {
26     n=read(),mod=read();
27     for(int i=1;i<=n;i++)
28     {
29         int g=exgcd(i,mod,x,y);
30         while(x<0)    x+=mod;
31         printf("%d\n",x);
32     }
33     return 0;
34 }

 

6.歐拉函數

  歐拉函數其實較好理解,但須要記住一些結論

  摘自:http://blog.csdn.net/w144215160044/article/details/51158735

  歐拉函數詳解

  1.對一個正整數N,歐拉函數是小於N且與N互質的數的個數.。

  2.例如φ(24)=8,由於1, 5, 7, 11, 13, 17, 19, 23均和 24 互質。

  3.φ(n) = n*(1-1/p1)*(1-1/p2)*......(1-1/pn)   其中(p1.....pn)爲N的素因子


歐拉函數的基本性質:

    ① N是不爲0的整數。φ(1)=1(惟一和1互質的數就是1自己)

    ② 除了N=2,φ(N)都是偶數.

    ③ 小於N且與N互質的全部數的和是φ(n)*n/2。//感受很重要...但又感受用不到

    ④ 歐拉函數是積性函數——若m,n互質,φ(m*n)=φ(m)*φ(n)。

    ⑤ 當N爲奇數時,φ(2*N)=φ(N)

    ⑥ 若N是質數p的k次冪,φ(N)=p^k-p^(k-1)=(p-1)p^(k-1),由於除了p的倍數外,其餘數都跟N互質。

    ⑦ 當N是質數時,φ(N) = N-1

 

 代碼:

 1 #include<bits/stdc++.h>
 2 #define man 110000
 3 #define sc(x) scanf("%d",&x)
 4 #define LL long long
 5 using namespace std;
 6 int n;
 7 int p[man];
 8 inline void ola()
 9 {
10     for(int i=1;i<=n;i++)
11         p[i]=i;
12     for(int i=2;i<=n;i++)
13     {
14         if(p[i]==i)
15         {
16             for(int j=i;j<=n;j+=i)
17                 p[j]=p[j]/i*(i-1);//或p[j]-=p[j]/i;
18             }
19         }
20     }
21 int main()
22 {
23     sc(n);
24     ola();
25     for(int i=1;i<=n;i++)
26         cout<<i<<" "<<p[i]<<endl;
27     return 0;
28     }

 

 1 inline int euler(int n)
 2 {    int ret=n;
 3     for(int i=2;i*i<=n;i++)
 4     {    if(n%i==0)
 5         {    ret-=ret/i;
 6             while(n%i==0)
 7                 n/=i;
 8             }
 9         }
10     if(n>1)
11          ret-=ret/n;
12     return ret;
13     }

 

   

  7.線性篩素數

  這也是考試的時候不能打錯的函數。十分重要的函數。

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<iostream>
 4 #include<cstring>
 5 #include<cstdlib>
 6 #define man 10000000
 7 using namespace std;
 8 int n,isprime[man],prime[man],p=0;
 9 inline void calcprime()
10 {
11     for(int i=2;i<=n;i++)
12     {
13         if(isprime[i]==0)
14         {    
15             prime[++p]=i;
16         }
17         for(int j=1;i*prime[j]<=n;j++)
18         {    
19             isprime[i*prime[j]]=1;
20             if(i%prime[j]==0)
21                 break;
22         }
23     }    
24 }
25 int main()
26 {    
27     memset(isprime,0,sizeof(isprime));
28     memset(prime,0,sizeof(prime));
29     cin>>n;
30     calcprime();
31     for(int i=1;i<=p;i++)
32         cout<<prime[i]<<endl;
33     return 0; 
34  } 

 

8.線性篩歐拉函數與素數

  很強大。。。

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <algorithm>
 4 #include <cstring>
 5 using namespace std;
 6 typedef long long ll;
 7 const int N=1e7+5;
 8 int n;
 9 bool vis[N];
10 int p[N],m=0;
11 ll s[N],ans,phi[N];
12 void sieve(){
13     phi[1]=1;
14     for(int i=2;i<=n;i++){
15         if(!vis[i]){
16             p[++m]=i;
17             phi[i]=i-1;
18         }
19         for(int j=1;j<=m&&i*p[j]<=n;j++){
20             vis[i*p[j]]=1;
21             if(i%p[j]==0){
22                 phi[i*p[j]]=phi[i]*p[j];
23                 break;
24             }
25             phi[i*p[j]]=phi[i]*(p[j]-1);
26         }
27     }
28     for(int i=1;i<=n;i++) s[i]=s[i-1]+phi[i];
29 }
30 int main(){
31     scanf("%d",&n);
32     sieve();
33     for(int i=1;i<=m;i++) ans+=s[n/p[i]];
34     printf("%lld",ans*2-m);
35 }

 

 

9.同餘方程組(中國剩餘定理)

注意:下面是洛谷典型的中國剩餘定理的題目(洛谷P1495 曹衝養豬)的代碼

   但我是用同餘方程組解的。

   代碼中同餘方程爲:P≡b(mod m)

  

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define ll long long
 4 inline ll read()
 5 {    ll x=0;bool f=0;char ch=getchar();
 6     while(!isdigit(ch)){    f=(ch==45);ch=getchar();}
 7     while(isdigit(ch)) {    x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
 8     return f?(~x+1):x;
 9     }
10 ll n,x,y;
11 ll b1,b2,m1,m2;
12 ll exgcd(ll a,ll b,ll &x,ll &y)
13 {    if(b==0)
14     {    x=1;y=0;return a;}
15     ll ret=exgcd(b,a%b,x,y);
16     ll t=x;x=y;y=t-(a/b)*y;
17     return ret;
18     }
19 int main()
20 {    n=read();
21     m1=read();b1=read();
22     for(int i=1;i<n;i++)
23     {    m2=read();b2=read();
24         ll A=m1,B=m2,k=b2-b1;
25         ll d=exgcd(A,B,x,y);
26         x=(((x*(k/d))%(B/d))+(B/d))%(B/d);//對x取最小正整數解
27         b1=m1*x+b1;//新的b1爲原來的P
28         m1=m1/d*m2;//新的m1爲LCU(m1,m2)
29         }
30     printf("%lld\n",b1);//由於b1始終是上一個同餘方程的P,天然for循環結束以後的b1爲題目所要求的P了
31     return 0;
32     } 
相關文章
相關標籤/搜索