數學整合:爲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 }