快速幂

16 篇文章 0 订阅
5 篇文章 0 订阅

快 速 幂

利用快速幂,可以极大提高运算速度,一般有数的快速幂,也有矩阵的快速幂,原理一样

a^b mod c=(a^2)^(b/2) mod c  (b为偶数); 

a^b mod c=((a^2)^(b div 2)*a) mod c (b为奇数)

利用位操作,很快!


【常规版(非快速幂法)】

int pow1( int a, int b ) {

  int r = a;

  while( b-- )

  r *= a;

  return r;

  }


【二分版】

  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;

  }


【位操作法(最是常用)】

  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;

  }


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

(我觉得吧,就快了一点点。。。)

  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;
  }


【矩阵快速幂(最是常用)】

#include 
     
     
      
      
#include 
      
      
       
       
#include 
       
       
        
        
#include 
        
        
         
         
#define sizer 3
using namespace std;

int N;

struct matrix {
    int a[sizer][sizer];
} origin,res;

matrix multiply(matrix x,matrix y)
{/**定义矩阵乘法,不过,都是方阵*/
    matrix temp;
    memset(temp.a,0,sizeof(temp.a));
    for(int i=0; i
         
         
           >=1; origin=multiply(origin,origin); } } void print(matrix m, int sizee) { for(int i=0; i 
           
         
        
        
       
       
      
      
     
     

boj428 田田的账号(规律+数值的快速幂)

题目描述

田田申请了一个新的oj账号,打算取一个霸气而简单的名字。 什么叫简单呢?说白了田田脑子不好使,只能记住abcd这4个字母组成单词。 怎么叫霸气呢?田田认为a个个数一定要有奇数个,b的个数一定要有偶数个(包括0)才可以。 现在田田取了一个长为n的账号,但是由于田田的记性实在太差了,而把账号忘记了. 于是把这个问题交给了聪明的wzt,而他认为这道题太过于简单就把这道题交给了你 究竟这个账号有多少种可能?你只需得到这个结果模 109+7 的值


输入样例

2(T,case数)
1(n取值)
2

输出样例

1
4

这道题目的规律我是老早就猜出来了,可是就是过不了啊过不了啊,这是为什么哩,一语点醒幂中人啊——“快速幂”

1.规律:打表也可以,不过动用一下逻辑思维可以直接推:

记a的个数为奇数,b的个数为偶数的账号排列数为A;

记a的个数为奇数,b的个数为偶数的账号排列数为B;很显然,有对称性,A=B,明显对不对;

你还会发现ab数对和cd数对也有对称性;

我们知道密码一共4的n次方个,两个对称性,除以2再除以2,结果就是4的n-1次方。

2.快速幂(快速幂取余):


当然啦,本题是要取余的,所以还是有所不同的。而且而且,必须要注意数的边界边界边界。。。

#include 
    
    
     
     
#define ko 1000000007/**这种雷打不动的数,用常量定义最好啦*/
int quickpow_mod(int a,int n,int k)
{
   
    int b=1; /**初始化这种东西,玩死人。。。*/
    long long int b_,a_;/**越界这种东西,直接让你死*/
    while(n>0){
        if(n & 1){
            b_=(long long)b;
            b_=(b_*a)%k;
            b=b_;
        }
        n=n>>1;
        a_=a;
        a_=(a_*a_)%k;
        a=a_;
    }
    return b;
    
}
int main()
{
    int t,n;
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        printf("%d\n",quickpow_mod(4,n-1,ko));
    }
}

    
    


hdu4686 Arc of Dream(矩阵快速幂)

题目描述

起始值 a0 = A0 ; b0 = B0 ;

递推式 ai = ai-1* AX + AY ; bi = bi-1* BX + BY ;

最后求 AoD(n)的值 mod 1,000,000,007


解题思路


首先,你得构造矩阵,这是个很麻烦的事,不过呢,如果你能写出递推式,那就没什么了,

来看这个式子:ai*bi=(ai-1 *ax+ay)*(bi-1 *bx+by)

                =(ai-1 * bi-1 *ax*bx)+(ai-1 *ax*by)+(bi-1 *bx*ay)+(ay*by)

看见了,和ai,bi相关联的事 ai-1*bi-1, ai-1, bi-1, 然后就全是常数了,于是我们想:

令 p=ax*bx,  q=ax*by,  r=ay*bx,  s=ay*by  s(n)=sum(ai*bi),i=0,1,...n

ai*bi=p(ai-1 * bi-1)+q(ai-1)+r(bi-1)+s  s(i)=s(i-1)+ai*bi 

对于任何一个递推式,我们都可以用矩阵法来优化,加快速度求出第n项或前n项和

=>

特别棒,以就该多学学怎么构造


输入输出

Sample Input
   
   
1(N,表示n,就是幂次) 1 2 3(分别对应 A0, AX, AY ) 4 5 6(分别对应 B0, BX, BY ) 2 1 2 3 4 5 6 3 1 2 3 4 5 6 (N <= 1018, and all the other integers <= 2×109.)
 

Sample Output
   
   
4 134 1902


解题总结

1. LL坑得好惨,一定要注意int 和 LL 的区别,为此我居然 TTTTT。。。

2. 当N为0时,要特判

3. 请保持随处取余的好习惯!!!


代码

#include 
    
    
     
     
#include 
     
     
      
      
#include 
      
      
       
       
#include 
       
       
        
        
#define sizer 5
#define modvalue 1000000007
using namespace std;
typedef long long ll;
ll a[sizer][sizer],res[sizer][sizer],temp[sizer][sizer];

void multiply(ll x[][5],ll y[][5])
{
    for(int i=0; i
        
        
          >=1; } } void print(ll m[][5], int sizee) { for(int i=0; i 
          
        
       
       
      
      
     
     
    
    

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值