挑戰2.6
阿新 • • 發佈:2018-12-14
1.gcd
gcd(a,b)=gcd(b,a%b)
#include<iostream> using namespace std; int gcd(int a,int b) { if(b==0)return a; return gcd(b,a%b); } int main() { int a,b; cin>>a>>b; cout<<gcd(a,b)<<endl; }View Code
2.extgcd
一個事實:對於二元一次方程ax+by=gcd(a,b)必存在整數解(x,y)
ax+by=gcd(a,b)
又bx1+(a%b)y1=gcd(b,a%b)=gcd(a,b)
等價於bx1+(a-(a/b)*b)y1=gcd(a,b)
等價於ay1+b(x1-(a/b)y1)=gcd(a,b)
那麼可以得到x=y1,y=x1-(a/b)y1
x1=y2,y1=x2-(a/b)y2
這樣一直遞迴下去,直到a%b=0,此時gcd(a,b)=a,解為xn=1,yn=0,回代就可以求出x和y
#include<iostream> using namespace std; int extgcd(int a,int b,int &x,intView Code&y)//計算ax+by=gcd(a,b)的整數解,返回gcd(a,b) { int ans=a; if(b!=0) { ans=extgcd(b,a%b,y,x); y-=(a/b)*x; } else{ x=1; y=0; } return ans; } int main() { int a,b,x,y; cin>>a>>b; cout<<extgcd(a,b,x,y)<<endl; cout<<x<<endl<<y<<endl; }
3.素數判斷
#include<iostream> using namespace std; bool is_prime(int x) { for(int i=2;i*i<=x;i++) { if(x%i==0)return false; } return x!=1; } int main() { int x; cin>>x; if(is_prime(x))cout<<"YES\n"; else cout<<"NO\n"; }View Code
4.埃氏篩
求1到n之間的素數
先將2到n所有的數字寫下來,做成一張表
對於最小的數字2,劃取表中所有2的倍數
表中剩餘的最小數字是3,劃去表中所有3的倍數
依次推下去,直到遍歷到表中最後一個數字n
#include<iostream> #include<vector> using namespace std; vector<int>prime; bool is_prime[1000005]; void sieve(int n) { for(int i=1;i<=n;i++)is_prime[i]=true; is_prime[0]=is_prime[1]=false; for(int i=2;i<=n;i++) { if(is_prime[i]) { prime.push_back(i); for(int j=2*i;j<=n;j+=i)is_prime[j]=false; } } } int main() { int n; cin>>n; sieve(n); cout<<prime.size()<<endl; }View Code
4.區間篩
對於兩個特別大的數a,b,求區間[a,b)內素數的個數
首先對於[a,b)內任意一個合數x,x的最小的因子(除去1)小於√b,那麼對於區間[2,√b)內的每一個素數,篩掉它在[a,b)內的倍數,[a,b)內剩下的數就是素數了
#include<iostream> #include<vector> using namespace std; typedef long long ll; bool is_prime1[1000005];//篩[2,sqrt(b)) bool is_prime2[1000005];//篩[a,b) vector<ll>prime;//記錄[a,b)中的素數 void segment_sieve(ll a,ll b) { for(int i=2;(ll)i*i<b;i++)is_prime1[i]=true; for(int i=1;i<=b-a;i++)is_prime2[i]=true; for(int i=2;(ll)i*i<b;i++) { if(is_prime1[i]) { for(int j=2*i;(ll)j*j<b;j+=i)is_prime1[j]=false; for(ll j=max(2LL,(a+i-1)/i)*i;j<b;j+=i)is_prime2[j-(a-1)]=false; } } for(int i=1;i<=b-a;i++) if(is_prime2[i])prime.push_back(i+a-1); } int main() { ll a,b; cin>>a>>b; segment_sieve(a,b); cout<<prime.size()<<endl; }View Code
5.快速冪
快速冪運算的演算法:反覆平方法
例如求x的22次方
22的二進位制是10110
10110從右到左分別對應x的1次方,x的2次方,x的4次方,x的8次方,x的16次方
二進位制含有1的位置是2,3,5,將這些位置對應的冪相乘就求得x得22次方
#include<iostream> using namespace std; typedef long long ll; int mod_pow(ll x,ll n,ll mod) { if(n==0)return 1%mod;//注意,mod可能是1!!! int res=mod_pow((x%mod)*(x%mod)%mod,n/2,mod); if(n&1)res=res*(x%mod)%mod; return res; } int main() { ll x,n,mod; cin>>x>>n>>mod; cout<<x<<"^"<<n<<" mod "<<mod<<"="<<mod_pow(x,n,mod)<<endl; }View Code