算法初章之快速幂相关

这几天做题的时候突然想稍微研究下这个。总结下快速幂的想法。

算理分析:

快速幂,顾名思义,是快速求解高次幂的算法。
其实这是用在密码学中的快速幂取模算法。
比如:
由取模定义:
56*89mod(a)=56mod(a)*89mod(a)。
可知:
56^56mod(1526)=56^55*56mod(1526)
=56^54mod(1526)*56^2mod(1526)
=56*56*56***56(56个)mod(1526)
这样就将一个非常大的数字的mod运算变成最多循环56次的mod运算。
算法:

typedef long long ll;
int quick_mod(int x, int n, int mod){
    ll res = 1;
    while (n > 0){
        if (n & 1)//与1与运算,判断是否为奇数
            res = res*x%mod;
        x = x*x%mod;
        n >>= 1;//二进制右移一位,相当于n/2,前面已经保证奇数时的运算了。
    }
    return res;
}

算法应用:

题目:
求x^n的最后3位数。

题目链接:HDU 2035 人见人爱A^B

那么只要quick_mod(x,n,1000);
即可。

原理剖析:(相关性分析)

求运算的最后三位。这是一个循环的乘法运算。
任何一个乘法计算后的数字,其后三位只和相乘两个数的后三位相关。
且为直接相关。
高于三位的数字与计算后数字的后三位无相关性。
因此,只要保留每次运算的后三位即可,即为每次运算mod(1000).

题目升级1:

题目:
求x^n的前面3位数。
题目连接:(前一位数)
http://acm.hdu.edu.cn/showproblem.php?pid=1060

相关性分析:

这个就不能直接套用取模运算了。因为题目要求的是最前面的,不是最后面的。
在乘法运算中,前两位的相关性与运算数字的前三位强相关。
之后就是依次与最后一位程递减关系。
那么只要保证参与运算的前几位足够的多,得到的最前面3位就越精确。
下面是算法:

typedef long long ll;
int quick_power(ll x,ll n)
{
    ll res = 1;
    while (n > 0 ){
        if (n & 1)
        {
            res = res*x;
            if (res > 1000000000)
            {//保证参与运算的数字有9位
                while (res > 1000000000)
                    res = res / 10;
            }
        }
        x = x*x;
        if (x > 1000000000)
        {//保证参与运算的数字有9位
            while (x >1000000000 )
                x = x / 10;
        }
        n >>= 1;
    }
    if (res >= 1000)
    {//获得前三位
        while (res >= 1000)
            res = res / 10;
    }
    return res;
}

简单的用几个循环测试了下。
当幂在10000以内时,出错概率大概为0.20002%,误差极小,误差范围也是<0.0001,大概是格式取值的时候出现点问题。
当幂在100000以内时,出错概率大概为2.262%,误差范围<0.001。

当测试为为最前面1位时。
幂在10000以内时,出错概率接近0%。
当幂在100000以内时,0.02300023%。

数学技巧运用:(精确)

求n^n。
可以运用高数中对数的解题技巧。
x=n^n
loga(x)=n*loga(n)
设m=loga(x) ->x=a^m 即x=pow(a,m)

令a=10,即等式两边同时取10的对数log10。
x ^ x= 10^(x*lg(x))=10^(整数部分+小数部分) ;则x ^ x的最高位是由小数部分决定的(因为10的整数次幂不会影响最高位,只在最末位加0)。
应用上面的技巧,可以快速的求得。
算法:

#include <cstdio>
#include <iostream>
#include <map>
#include <algorithm>
#include <cmath>
#include <vector>
#include <functional>
#include <string>
using namespace std;
typedef long long ll;
int main()
{
    ll m = 99999;
    int T;
    cin >> T;
    int  n, i, ans, num = 0, k;
    double a, b;
    //for (; m > 1; m = m - 1)
    //{
    while (T--){
        scanf("%Id64", &m);
        //k = getmod(m, m);
        a = m*log10(m*1.0) - (long long)(m*log10(m*1.0));
        b = pow((double)10, a);
        //b = b * 100;
        ans = (int)(b);
        cout << ans << endl;
    }
}

话说,我前面还那么麻烦干什么?0 0。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值