#快速幂#POJ 2991 2011&&luogu 1226 取余运算

7 篇文章 0 订阅
5 篇文章 0 订阅

2011

已知长度最大为200位的正整数n,请求出2011^n的后四位。
总时间限制: 1000ms 内存限制: 65536kB

输入

第一行为一个正整数k,代表有k组数据,k<=200接下来的k行, 每行都有一个正整数n,n的位数<=200

输出

每一个n的结果为一个整数占一行,若不足4位,去除高位多余的0
样例输入
3
5
28
792
样例输出
1051
81
5521

知识储备

  • a*b%k=(a%k)*(b%k)%k
  • b^0%k=1
  • p=2*(p/2)+p%2(p为任意自然数)
  • b^p%k=(b^(p/2))^2%k(p为偶数)
  • b^p%k=(b^(p/2))^2*b%k(p为奇数)
  • 快速幂思想
#include<cstdio>
#include<cstring>
#include<cstdlib> 
using namespace std; 
long long k,a[505],x;
char c[205],s[5];
int fz(int x)
{
    if (x==0) return 2011;
    if (x==1) return 2011;
    int t=fz(x/2)%10000;//递归分解
    t=t*t%10000;//逐步平方 将乘幂分解为许多小数一步步相乘
    if (x%2==1) t*=2011%10000;//x为奇数比x为偶数多乘一次底数 见知识储备
    return t;
} 
int main()
{
    scanf("%d",&k);
    for (int i=1;i<=k;i++)
    {
        scanf("%s",c);
        if (strlen(c)>3)//如果不加这个判断 j的初始值会<0 500以下的数全部输出1
        {
            for (int j=strlen(c)-3;j<strlen(c);j++)
                s[j-strlen(c)+3]=c[j];
            x=(atoi(s))%500;//500次一循环 第500次是1 第501次是2011 
        } else x=(atoi(c))%500;
        a[0]=1; a[1]=2011;
        for (int j=2;j<=x;j++)
            a[j]=fz(j)%10000;
        printf("%d\n",a[x]);
    }
}
  • 相关问题
    信息学奥赛一本通p289例7.5 || luogu p1226:

取余运算

输入b,p,k的值,求b^p mod k的值。其中b,p,k*k为长整型数。

输入输出格式

输入格式:
三个整数b,p,k.

输出格式:
输出“b^p mod k=s”

s为运算结果

输入输出样例

输入样例#1:
2 10 9
输出样例#1:
2^10 mod 9=7

  • 以下摘自luogu题解

很明显,对于每一个n^x,若x为偶数,则n^x=(n*n)^x/2。若x为奇数,则n^x=(n*n)^x/2*n。那么我们就能轻松的用简单的递归解决快速幂。
代码如下:

#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
long long b,p,k,ans;
long long qpow(long long n,long long x,long long mod)
{
    if(x==0) return 1;//递归出口:0次方为1
    long long res=qpow(n*n%mod,x/2,mod);//递归
    if(x&1) res=res*n%mod;//若x为奇数那么把返回值乘上n
    return res;
}
int main()
{
    scanf("%lld%lld%lld",&b,&p,&k);
    ans=qpow(b,p,k);
    printf("%lld^%lld mod %lld=%lld",b,p,k,ans);
    return 0;
}
  • 以下为课本原文算法分析

本题主要的难点在于数据规模很大(b,p都是长整型数),对于b^p显然不能死算,那样的话时间复杂度和编程复杂度都很大.
下面先介绍以下原理:a*b%k=(a%k)*(b%k)%k.显然有了这个原理,就可以八较大的幂分解成较小的幂,因而免去高精度计算等复杂过程.那么怎样分解最有效呢?显然对于任何一个自然数p,有p=2*p/2+p%2,如19=2*19/2+19%2=2*9+1,利用上述原理就可以把b的19次方除以k的余数转换为求b的9次方除以k的余数,即b^19=b^(2*9+1)=b*b^9*b^9,再进一步分解下去就不难求得整个问题的解
相似标程:

#include<iostream>
#include<cstdio>
using namespace std;
int b,p,k;
int f(int); //利用分治求b^p%k

int main(){
    scanf("%d%d%d",&b,&p,&k);//输入三个数
    int temp=b;//将b的值备份
    b%=k;//防止b太大
    printf("%d^%d mod %d=%d\n",temp,p,k,f(p));
    return 0;
}

int f(int p){
    if(p==0){  //b^0%k=1
        return 1;
    }
    int tmp=f(p/2)%k;
    tmp=(tmp*tmp)%k;  //b^p%k=(b^(p/2))^2%k
    if(p%2==1){
        tmp=(tmp*b)%k; //如果p为奇数,则b^p%k=((b^(p/2))^2)*b%k;
    }
    return tmp;
}

快速幂及其原理

快速幂顾名思义,就是快速算某个数的多少次幂。
其时间复杂度为 O(log2N), 与朴素的O(N)相比效率有了极大的提高。
以下以求a的b次方来介绍
把b转换成2进制数
该2进制数第i位的权为(2^(i-1))
例如
a^11=a^(2^0+2^1+2^3)
11的二进制是1 0 1 1
11 = 2^3*1 + 2^2*0 + 2^1*1 + 2^0*1
因此,我们将a^11转化为算a^(2^0)*a^(2^1)*a^(2^3)
快速幂可以用位运算这个强大的工具实现
b & 1 //也就是取b的二进制最末位(and)
b >> 1 //就是去掉b的二进制最末位(shr 右移)

基本模板

int pow3( int a, int b ) {
int r = 1, base = a;
while( b != 0 ) 
{
    if( b & 1 )
    r *= base;
    base *= base;//base*base即求出了a^(2^(i-1))
    b >>= 1;
}
return r;  
  • 更高效率的位运算法:
int power4(int x, int n)
{
    if (n == 0) return 1;
    else
        while ((n & 1) == 0)
        {
            n >>= 1;
            x *= x;
        }
    int result = x;
    n >>= 1;
    while (n != 0)
    {    
        x *= x;
        if ((n & 1) != 0) result *= x;
        n >>= 1;
    }
    return result;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值