二分幂、快速幂、矩阵快速幂、幂取模

20 篇文章 0 订阅
19 篇文章 0 订阅

二分幂:如计算a^n;如果n为偶数,则计算a^n/2(递归到n=0),再计算(a^n/2)(a^n/2),就可得出结果;如果n为奇数,则先计算a^(n-1)/2(递归到n=0),再计算(a^(n-1)/2)*(a^(n-1)/2)a,就可得出结果。

long long fun(int a,int b)
{
    if (b==0)
        return 1;
    if (b==1)
        return a;
    long long ans=fun(a,b/2);
        ans*=ans;
    if (b%2==1)
        ans*=a;
    return ans;
}

快速幂:如计算经典的2^11;11的二进制为1011,2^3*1+2^2*0+2^1*1+2^0*1,2^(2^3*1+2^2*0+2^1*1+2^0*1)。

一般方法:

long long fun( int a, int b ) 
{
    long long r = 1;
    int base = a;
    while( b != 0 ) 
    {
        if( b % 2 )//判断奇偶性
        r *= base;
        base *= base;
        b /= 2;//与b>>1相同
    }
    return r;
}

位运算:

long long fun( int a, int b ) 
{
    long long r = 1;
    int base = a;
    while( b != 0 ) 
    {
        if( b & 1 )//判断奇偶性
        {
            r *= base;
        }
        base *= base;
        b >>= 1;//与b/2相同
    }
    return r;
}

矩阵快速幂:

/**************************************************************
FZU 2198 矩阵快速幂 + 矩阵乘法优化 + 打表 + 广义Fibonacci数列找循环节
F(n) = a * F(n - 1) + b * F(n - 2)
a^2 + 4b是模p的二次剩余时,枚举n = p - 1的因子
a^2 + 4b是模p的二次非剩余时,枚举n = (p + 1)(p - 1)的因子
找到最小的循环节
**************************************************************/
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define LL long long
const LL mod = 1000000007;
struct Matrix
{
    int row, col;
    LL m[4][4];
    void init(int row, int col)
    {
        this->row = row;
        this->col = col;
        for (int i = 0; i < row; ++i)
            for (int j = 0; j < col; ++j)
                m[i][j] = 0;
    }
} A, pp[66], ans;
Matrix operator*(const Matrix & a, const Matrix& b)
{
    Matrix res;
    res.init(a.row, b.col);
    for (int k = 0; k < a.col; ++k)
    {
        for (int i = 0; i < res.row; ++i)
        {
            if (a.m[i][k] == 0 ) continue;
            for (int j = 0; j < res.col; ++j)
            {
                if (b.m[k][j] == 0 ) continue;
                res.m[i][j] = (a.m[i][k] * b.m[k][j] + res.m[i][j]) % mod;
            }
        }
    }
    return res;
}
void init()
{
    Matrix qq;
    A.init(3, 1);
    A.m[0][0] = 7;
    A.m[1][0] = 1;
    A.m[2][0] = 1;

    qq.init(3, 3);
    qq.m[0][0] = 6;
    qq.m[0][1] = -1;
    qq.m[0][2] = 1;
    qq.m[1][0] = 1;
    qq.m[2][2] = 1;
    pp[0] = qq;
    for (int i = 1; i < 64; i++)
        pp[i] = pp[i - 1] * pp[i - 1];
}
void Cal(LL a)
{
    for (int i = 0; a; i++, a >>= 1)
    {
        if (a & 1)
        {
            ans = pp[i] * ans;
        }
    }
    return ;
}
int main()
{
    int T;
    LL n;
    init();
    scanf("%d", &T);
    while (T--)
    {
        scanf("%I64d", &n);
        ans = A;
        LL tmp = (n - 1) % 500000003;
        Cal(tmp);
        printf("%I64d\n", (ans.m[0][0] - 1 + mod) % mod);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值