挑战2.6

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,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;
} 
View Code

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

猜你喜欢

转载自www.cnblogs.com/lyhhahaha/p/10120954.html