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; }
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,int &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"; }
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; }
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; }
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; }