幂取模 poj 1995

昨天上午看了一下关于幂取模的方法,当时对于书上所说的反复平方的方法不是很理解,下去后也忘了上网搜下了!

今天晚上兴致大起,就上网搜了一个关于幂取模的方法(著名的RSA公钥的加密方法)!

这种方法利用了一种分治的思想,达到了O(log(n))!

对于形如a^b%c的式子:

可以把b按二进制展开为b=p(n)*2^n+p(n-1)*2^(n-1)+...+p(1)*2+p(0)
其中p(i) (0<=i<=n)为0或1
这样a^b=a^(p(n)*2^n+p(n-1)*2^(n-1)+...+p(1)*2+p(0))
       =a^(p(n)*2^n)*a^(p(n-1)*2^(n-1))*...*a^(p(1)*2)*a^p(0)
对于p(i)=0的情况,a^p(i)*2^(i-1)=a^0=1,不用处理
我们要考虑的仅仅是p(i)=1的情况
a^(2^i)=(a^(p(i)*2^(i-1)))^2
利用这一点,我们可以递推地算出所有的a^(2^i)
我们加上取模运算a^(2^i)%c=((a^(2^(i-1))%c)*a^(2^(i-1)))%c
于是再把所有满足p(i)=1的a^(2^i)%c按照算法1乘起来再%c就是结果!

当然也可以进一步的改进,可以不用存b的二进制,可以边求边用!

代码如下:

int mod(int a,int b,int c)
{  
 int k=1;
 if(b==0) return 1%c;
 while(b>=1)
 {
  if(b%2!=0) k=a*k%c;
  a=a*a%c;如果a*a会超过int的范围,可以改为a=((a%c)*(a%c))%c;
  b/=2;
 }
 return k;
}

pku 1995 就是单纯的幂取模!

代码如下:

ContractedBlock.gif ExpandedBlockStart.gif 代码
 
   
1 # include < stdio.h >
2   int mod( int a, int b, int c)
3 {
4 int k = 1 ;
5 if (b == 0 ) return 1 % c;
6 while (b >= 1 )
7 {
8 if (b % 2 != 0 ) k = a * k % c;
9 a = ((a % c) * (a % c)) % c; /// /由于a比较大!
10   b /= 2 ;
11 }
12 return k;
13 }
14 int main()
15 {
16 int i,t,M,A[ 45005 ],B[ 45004 ],H,sum;
17 scanf( " %d " , & t);
18 while (t -- )
19 {
20 scanf( " %d%d " , & M, & H);
21 sum = 0 ;
22 for (i = 1 ;i <= H;i ++ )
23 {
24 scanf( " %d%d " , & A[i], & B[i]);
25 sum += mod(A[i],B[i],M);
26 sum %= M;
27 }
28 printf( " %d\n " ,sum);
29 }
30 return 0 ;
31 }
32

转载于:https://www.cnblogs.com/183zyz/archive/2010/11/18/1881130.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值