fpow!快速幂是怎么简化处理过程的

 取模运算法则

  1. (a + b) % p = (a % p + b % p) % p (1)

  2. (a - b) % p = (a % p - b % p ) % p (2)

  3. (a * b) % p = (a % p * b % p) % p (3)

 当然,为了解决多次乘法(n次幂),我们只需要关注第三条,每一次乘以底数的同时对结果取模。

HDU例题(可解,就先看看虽然谈不上快)

/**
 * 普通的求幂函数
 * @param base 底数
 * @param power  指数
 * @return  求幂结果的最后3位数表示的整数
 */
long long normalPower(long long base,long long power){
    long long result=1;
    for(int i=1;i<=power;i++){
        result=result*base;
        result=result%1000;
    }
    return result%1000;
}

关于整数范围

Int 的 范围:-2147483648 ~ 2147483647 20亿 >1e9+7 Long 的 围:-9223372036854775808 ~ 9223372036854775807 < 1e20

HRBUST例题的一部分(Jay)(可解,可AC但是不严格)


#include<bits/stdc++.h>
const int mod=1e9+7;
using namespace std;
int main(){
    

	clock_t start, finish;//clock_t为CPU时钟计时单元数
    int ans=1,ci=0;
    scanf("%d",&ci);
    start = clock();//导出当前计时单元数 
    for(int i=1;i<=ci;i++){
    	
        ans=2*ans%mod;
        
    }
    finish=clock();
    cout<<ans<<endl;
    cout << "the time cost is" << double(finish-start) / CLOCKS_PER_SEC;//finish与start的差值即为程序运行花费的CPU时钟单元数量,再除每秒CPU有多少个时钟单元,即为程序耗时
   }

//输入100000000 the time cost is0.333 
//输入1000000000 the time cost is3.288
/*
BUTBUTBUTBUT!!!
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K 
*/

加速!加速!快速幂!(别人的详细文

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 1e9+7;
const ll N = 1e8+10;
char ch[N];

//快速幂——————————————————————————————————————

ll fpow(ll a,ll b){

a%=mod;
ll res = 1;

while(b){
if(b&1) 
res=res*a%mod;
a=a*a%mod;
b>>=1;//快!
}

return res;

}

//快速幂——————————————————————————————————————

int main()
{
    scanf("%s",ch);//用scanf读取字符串的方式!
    ll sum = 0,a = 0,b = 0,c = 0;
    for (int i = 0; i <strlen(ch); i++)
    {
        if(ch[i]=='J'&&ch[i+1]=='a'&&ch[i+2]=='y'&&i<strlen(ch)-2) sum++;//连着的Jay
        if(ch[i]=='J')   a++;
        else if(ch[i]=='a')   b++;
        else if(ch[i]=='y')   c++;
    }
    ll total = min(min(a,b),c);//Jay总数
    ll sub = total-sum;//非连着的
    if(total==0)  {printf("0");return 0;}//如果Jay为0
    else if(total==1)    {printf("1");return 0;}//如果Jay为1
    else if(sum==0) {printf("%lld",total);return 0;}//如果没有连着的Jay
    else
    {
        if(sub==0)  sub = fpow(2,sum-1);//如果Jay全是连着的,那么sub就等于0了,需要特判
        else    sub = sub*fpow(2,sum)%mod;//一般情况,别忘了再对mod取余!
    }
    printf("%lld",sub);
    return 0;
}

引:

快速幂算法能帮我们算出指数非常大的幂,传统的求幂算法之所以时间复杂度非常高(为O(指数n)),就是因为当指数n非常大的时候,需要执行的循环操作次数也非常大。所以我们快速幂算法的核心思想就是每一步都把指数分成两半,而相应的底数做平方运算。这样不仅能把非常大的指数给不断变小,所需要执行的循环次数也变小,而最后表示的结果却一直不会变。

3^10=3*3*3*3*3*3*3*3*3*3

//尽量想办法把指数变小来,这里的指数为10

3^10=(3*3)*(3*3)*(3*3)*(3*3)*(3*3)

3^10=(3*3)^5

3^10=9^5

//此时指数由10缩减一半变成了5,而底数变成了原来的平方,求3^10原本需要执行10次循环操作,求9^5却只需要执行5次循环操作,但是3^10却等于9^5,我们用一次(底数做平方操作)的操作减少了原本一半的循环量,特别是在幂特别大的时候效果非常好,例如2^10000=4^5000,底数只是做了一个小小的平方操作,而指数就从10000变成了5000,减少了5000次的循环操作。

//现在我们的问题是如何把指数5变成原来的一半,5是一个奇数,5的一半是2.5,但是我们知道,指数不能为小数,因此我们不能这么简单粗暴的直接执行5/2,然而,这里还有另一种方法能表示9^5

9^5=(9^4)*(9^1)

//此时我们抽出了一个底数的一次方,这里即为9^1,这个9^1我们先单独移出来,剩下的9^4又能够在执行“缩指数”操作了,把指数缩小一半,底数执行平方操作

9^5=(81^2)*(9^1)

//把指数缩小一半,底数执行平方操作

9^5=(6561^1)*(9^1)

//此时,我们发现指数又变成了一个奇数1,按照上面对指数为奇数的操作方法,应该抽出了一个底数的一次方,这里即为6561^1,这个6561^1我们先单独移出来,但是此时指数却变成了0,也就意味着我们无法再进行“缩指数”操作了。

9^5=(6561^0)*(9^1)*(6561^1)=1*(9^1)*(6561^1)=(9^1)*(6561^1)=9*6561=59049

我们能够发现,最后的结果是9*6561,而9是怎么产生的?是不是当指数为奇数5时,此时底数为9。那6561又是怎么产生的呢?是不是当指数为奇数1时,此时的底数为6561。所以我们能发现一个规律:最后求出的幂结果实际上就是在变化过程中所有当指数为奇数时底数的乘积。
————————————————
版权声明:本文为CSDN博主「刘扬俊」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_19782019/article/details/85621386

于是我们改成这样  


#include<bits/stdc++.h>
const long mod=1e9+7;
using namespace std;
int main(){
    

	clock_t start, finish;//clock_t为CPU时钟计时单元数
    long long ci=0,base=2,result=1;
    scanf("%lld",&ci);
    start = clock();//导出当前计时单元数 
    
    
    

    while (ci > 0) {
        if (ci % 2 == 1) {//判断奇数
            result = result * base % mod;//不要忘了一次方
        }
        ci = ci / 2;//ci>>=1更快
        base = (base * base) % mod;
    }

  


    
    finish=clock();
    cout<<result<<endl;
    cout << "the time cost is" << double(finish-start) / CLOCKS_PER_SEC;//finish与start的差值即为程序运行花费的CPU时钟单元数量,再除每秒CPU有多少个时钟单元,即为程序耗时
   }
//before: 
//输入100000000 the time cost is0.333 
//输入1000000000 the time cost is3.288
/*
BUTBUTBUTBUT!!!
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K 
*/
//now:
//输入100000000 the time cost is0
//输入1000000000 the time cost is0

再看看这种写法 


ll fpow(ll a,ll b){

a%=mod;
ll res = 1;

while(b){
if(b&1) //位运算 与 0001&000?判断奇数
res=res*a%mod;
a=a*a%mod;
b>>=1;//位运算 移位 相当于/2
}

return res;

}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

O&REO

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值