历届试题 小数第n位--快速幂算法

题目:

我们知道,整数做除法时,有时得到有限小数,有时得到无限循环小数。
  如果我们把有限小数的末尾加上无限多个0,它们就有了统一的形式。
  本题的任务是:在上面的约定下,求整数除法小数点后的第n位开始的3位数。

输入格式

  一行三个整数:a b n,用空格分开。a是被除数,b是除数,n是所求的小数后位置(0<a,b,n<1000000000)

输出格式

  一行3位数字,表示:a除以b,小数后第n位开始的3位数字。

样例输入

1 8 1

样例输出

125

样例输入

1 8 3

样例输出

500

样例输入

282866 999000 6

样例输出

914

思路:

由于数据的范围很大,如果按照一般的算法进行计算,那么一定会超时;

也不能够用double s=a/b*10^(n+2),数据太大,double的精确度不够,所以我们要找到一个合适的算法进行求解;

最合适的算法就是快速幂算法--反复平方;

快速幂算法--反复平方:

A:

当 X^n=((X^2)^2)......;

如果把n表示为2的幂次的和:n=2^k1+2^k2+2^k3+.....;

那么X^n=(x^2^k1)(x^2^k2)(x^2^k3).......;

时间复杂度就是O(logn);

例如:

x^22=x^16*x^4*x^2;      (22转换成二进制是10110);

ll qq(ll n,ll k)
{
    ll ret=1;
    while(k)
    {
        if(k&1)//如果二进制最低位为1,则乘上n^(2^i);
            ret=((ret%mod)*(n%mod))%mod;
        n=(n%mod)*(n%mod);//将n平方;
        k>>=1;//右移一位,相当于除2;
    }
    return ret%mod;
}

B:

也可以用另外一种思路来理解;

当n为偶数的时候有X^n=((x^2)^(n/2)),递归转为n/2的情况;

当n为奇数时有X^n=((x^2)^(n/2))*x;同样也递归转为n/2的情况。

这样递归下去,每次n都减半,于是可以在O(logn)时间内完成幂运算;

ll qq(ll n,ll k)
{
    if(k==0)
        return 1;
    ll ret=qq(n*n%mod,k/2);
    if(k&1)
        ret=ret*n%mod;
    return ret%mod;
}

代码如下:

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
typedef long long ll;

ll a,b,n,mod;

ll qq(ll n,ll k)
{
    ll ret=1;
    while(k)
    {
        if(k&1)//如果二进制最低位为1,则乘上n^(2^i);
            ret=((ret%mod)*(n%mod))%mod;
        n=(n%mod)*(n%mod);//将n平方;
        k>>=1;//右移一位,相当于除2;
    }
    return ret%mod;
}

/*ll qq(ll n,ll k)
{
    if(k==0)
        return 1;
    ll ret=qq(n*n%mod,k/2);
    if(k&1)
        ret=ret*n%mod;
    return ret%mod;
}*/


int main()
{
    while(~scanf("%lld%lld%lld",&a,&b,&n))
    {
        mod=b*1000;
        ll sum=(a%mod*qq(10,n+2))%mod;
        ll s=sum/b;
        printf("%lld\n",s);
    }
    return 0;
}

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值