次方求模

次方求模

时间限制:1000 ms  |  内存限制:65535 KB
难度:3
描述

求a的b次方对c取余的值

 

输入
第一行输入一个整数n表示测试数据的组数(n<100)
每组测试只有一行,其中有三个正整数a,b,c(1=<a,b,c<=1000000000)
输出
输出a的b次方对c取余之后的结果
样例输入
3
2 3 5
3 100 10
11 12345 12345
样例输出
3
1
10481
 
#include<stdio.h>

int main(){

	int n;
	long long  a, b, c;
	long long ans;
	scanf("%d",&n);

	while(n--){

		ans = 1;
		scanf("%lld%lld%lld", &a, &b, &c);
			while(b){

				if(b & 1)
					ans =(ans * a) % c; 	
				a =(a * a) % c;
				b >>= 1;
			}
			printf("%lld\n", ans);
	}
	return 0;
}        

乘法取模:xy mod n = (x mod n)(y mod n)mod n

加法取模: (x + y)mod n = ((x mod n) + (y mod n)) mod n
详见挑战编程 128页

【转】快速求幂:     

2原理

把b转换成二进制数
该二进制数第i位的权为
例如
11的二进制是1011
11 = 2³×1 + 2²×0 + 2¹×1 + 2º×1
因此,我们将a¹¹转化为算

3实现

快速幂可以用位运算这个强大的工具实现
1
b and 1 {也就是取b的二进制最末位}
1
b shr 1 {就是去掉b的二进制最末位}
有了这个强大的工具,快速幂就好实现了!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
var a,b,n:int64;
 
function f(a,b,n:int64):int64;
var t,y:int64;
begin
    t:=1;y:=a;
    while b<>0 do
    begin
        if (b and 1)=1 then t:=t*y mod n;
        y:=y*y mod n;
        {
            这里用了一个很强大的技巧,y*y即求出了
            a^(2^(i-1))
            不知道这是什么的看原理
        }
        b:=b shr 1;    {去掉已经处理过的一位}
    end;
    exit(t);
end;
 
begin
    read(a,b,n); {n是模}
    writeln(f(a,b,n));
end.
[1]

4代码比较

常规求幂

1
2
3
4
5
6
7
int pow1( int a, int b )
{
    int r = 1;
    while( b-- )
        r *= a;
    return r;
}

二分求幂(一般)

1
2
3
4
5
6
7
8
9
10
11
12
int pow2( int a, int b )
{
    int r = 1, base = a;
    while( b != 0 )
    {
        if( b % 2 )
            r *= base;
        base *= base;
        b /= 2;
    }
    return r;
}

快速求幂(位操作)

1
2
3
4
5
6
7
8
9
10
11
12
int pow3( int a, int b )
{
    int r = 1, base = a;
    while( b != 0 )
    {
        if( b & 1 )
            r *= base;
        base *= base;
        b >>= 1;
    }
    return r;
}

快速求幂(更高效率的位运算法)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
int pow4(int x, int n)
{
    int result;
    if (n == 0)
        return 1;
    else
    {
        while ((n & 1) == 0)
        {
            n >>= 1;
            x *= x;
        }
    }
    result = x;
    n >>= 1;
    while (n != 0)
    {   
        x *= x;
        if ((n & 1) != 0)
            result *= x;
        n >>= 1;
    }
    return result;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值