数论

一、快速幂函

求a的b次方,如果b很大,那么执行效率就是很低,可以利用 a^(2b) = a^b 乘以a^b进行优化。

#include<iostream>
using namespace std;
int Pow(int a,int b)
{
    if(b == 0)
        return 1;
    if(b&1)
        return a*Pow(a,b-1);
    else{
        int t = Pow(a,b/2);
        return t*t;
    }
}
int main()
{
    int a,b;
    while(cin>>a>>b)
    {
        cout<<Pow(a,b)<<endl;
    }
}
//非递归
#include<iostream>

using namespace std;

int Pow(int a,int b)
{
    int result = 1;
    int base = a;
    while(b){
        if(b&1)
            result *= base;
        base *= base; 
        b /= 2;
    }
    return result;
}
int main()
{
    int a,b;
    while(cin>>a>>b){
        cout<<Pow(a,b)<<endl;
    }
}

二、快速幂取模

如果先求a^b,再进行求余,当b很大时效率会很低。根据公式(a*b)mod c  =  [(a mod c) * (b mod c)] mod c以及快速幂可以进行优化。

#include<iostream>

using namespace std;

int PowMod(int a,int b,int c)
//(a^b)mod c
{
    int result = 1;
    int base = a%c;
    while(b)
    {
        if(b&1) //幂为奇数时的操作,结果乘以基数(因为奇数时可能是b=1,操作后为输出结果)
            result = (result*base)%c;  
        base = (base*base)%c;
        b /=2;
    }
    return result;
}

int main()
{
    int a,b,c;
    while(cin>>a>>b>>c)
    {
        cout<<PowMod(a,b,c)<<endl;
    }
}

三、等比数列二分求和取模

S n = a+a 2 +...+a n
要求 S n mod p
如果用公式算,可能溢出,因此用二分法求
1)  若 n 是偶数
S n = a+...+a n/2  + a n/2+1 + a n/2+2  +...+ a n/2+n/2
=(a+...+a n/2 ) + a n/2 (a+...+a n/2 )
=S n/2 + a n/2 S n/2
=(1+a n/2 )S n/2


2)  若n 是奇数
S n = a+...+a (n-1)/2  + a (n-1)/2+1 +...
+ a (n-1)/2+(n-1)/2 + a (n-1)/2+(n-1)/2 + 1
=S (n-1)/2 + a (n-1)/2 (a+...+a (n-1)/2 )+a n
=(1+a (n-1)/2 )S (n-1)/2 +a n

结合公式:( a+b)mod c = ( (a mod c) + (b mod c) ) mod c;

附:运用递归关系的三个条件 

1、可以把要解决的问题转化为一个新问题,而这个新的问题的解决方法仍与原来的解决方法相同,只是所处理的对象有规律地递增或递减。
2、可以应用这个转化过程使问题得到解决。
3、必定要有一个明确的结束递归的条件。

#include<iostream>

using namespace std;

int PowMod(int a,int b,int c)
{
    int result = 1;
    int base = a%c;
    while(b)
    {
        if(b&1)
            result = (result * base)%c;
        base = (base * base)%c;
        b /= 2;
    }
    return result;
}

int PowSumMod(int a,int n,int p)
{
    if(n == 1)
        return a%p;
    else{
        if(n%2 == 0)
            return (1 + PowMod(a,n/2,p) ) * PowSumMod(a,n/2,p) % p;
        else
            return ((1 + PowMod(a,(n-1)/2,p)) * PowSumMod(a,(n-1)/2,p) + PowSumMod(a,n,p) ) % p;
    }
}
int main()
{
    int a,n,p;
    while(cin>>a>>n>>p)
    {
        cout<<PowSumMod(a,n,p)<<endl;
    }
}

四、线性筛法求素数

求给定范围内的所有素数。

为了防止重复删数,进行改写得:

    #include<cstdio>
    #include<iostream>
    #include<vector>
    using namespace std;
    int main()
    {
        int n;
        cin>>n;
        vector<int>prime;
        vector<bool>is_prime(n+1);
        for(int i = 1;i <= n;i++){
            is_prime[i] = true;
        }
        for(int i = 2;i <= n;i++){
            if(is_prime[i])
                prime.push_back(i);
            for(int j = 0;j < prime.size();j++){
                if(i*prime[j] <= n)
                    is_prime[i*prime[j]] = false;
                else
                    break;
            }
        }
        for(int i = 0;i < prime.size(); ++i)
            cout << prime[i] << endl;
            return 0;
    }

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值