算法 {快速幂,快速乘}

算法 {快速幂,快速乘}

快速幂

定义

a k = ∏ a b 1 a^k = \prod a^{b_1} ak=ab1 where k ∈ Z + , a ∈ Z , ∑ b i = k , b i  为二次幂 k \in Z^+, a \in Z, \sum b_i = k, b_i \text{ 为二次幂} kZ+,aZ,bi=k,bi 为二次幂;

比如 a 10 = a ∗ a ∗ . . . a^{10} = a*a*... a10=aa...
. 因为 10 = 101 0 2 = 100 0 2 + 1 0 2 = 8 + 2 10 = 1010_2 = 1000_2 + 10_2 = 8 + 2 10=10102=10002+102=8+2, 所以 a 10 = ( 2 8 ) ∗ ( a 2 ) a^{10} = (2^8) * (a^2) a10=(28)(a2)

错误

在取模条件下, 底数可以取模, 但指数不可以;
a b a^b ab 等同于 ( a % m ) b (a\% m)^b (a%m)b;
. a b a^b ab 不等同于 a b % m a^{b \% m} ab%m, 比如 2 3 ( % 3 ) = 2 2^3 (\% 3) = 2 23(%3)=2 2 3 % 3 = 1 2^{3 \% 3} = 1 23%3=1;

算法模板

//{ KMI-Declaration
template< class _Type> _Type KMI( long long, long long, _Type);
//} KMI-Declaration

//{ KMI-Implementation
template< class _Type> _Type KMI( long long _base, long long _power, _Type _mod){
//<
// @含义
// . 该算法核心是使用`a*b`这个乘法 (`a,b`都是`[0,mod)`范围), 显然 如果`mod*mod`溢出了`long long`, 那么直接乘法就用不了了;
// . 因此, 当`mod*mod`不会溢出`long long` 你需要定义`__KMI_IS_NORMAL_`这个宏为`1` (这也是默认定义);
// . 否则, 如果会溢出 则需要使用*快速乘* (即将`a*b` 转换为`a+b`) 你需要将`__KMI_IS_NORMAL_`这个宏 定义为`0`;
// @耗时
//   @IF( `__KMI_IS_NORMAL_` == 1) `ln(_power)`;
//   @ELIF( `__KMI_IS_NORMAL_` == 0) `ln(_power) * ln(_power)`;
    ASSERT_( _mod >= 1 && _mod <= 9223372036854775807LL / 2);
    //--
#define  __KMI_IS_NORMAL_  1
    ASSERT_( ((_mod <= 9223372036854775807LL / _mod) && __KMI_IS_NORMAL_)
                || ((_mod > 9223372036854775807LL / _mod) && (0 == __KMI_IS_NORMAL_)));
    _Type ans = 1 % _mod;
    _base %= _mod;  if( _base < 0){ _base += _mod;}
    while( _power > 0){
        if( _power & 1){
#if  __KMI_IS_NORMAL_
            ans = _base * ans % _mod;
#else
            ans = Binary_Multiplication< _Type>( _base, ans, _mod);
#endif
        }
#if  __KMI_IS_NORMAL_
            _base = _base * _base % _mod;
#else
            _base = Binary_Multiplication< _Type>( _base, _base, _mod);
#endif
        _power >>= 1;
    }
    return ans;
#undef  __KMI_IS_NORMAL_
}
//} KMI-Implementation

快速乘

定义

a ∗ b = a ∗ ∑ b i a * b = a * \sum b_i ab=abi, 其中 ∑ b i = b , b i 为二次幂 \sum b_i = b, b_i \text{为二次幂} bi=b,bi为二次幂;

算法模板

//{ Binary_Multiplication-Declaration
template< class _Type> _Type Binary_Multiplication( long long, long long, _Type);
//} Binary_Multiplication-Declaration

//{ Binary_Multiplication-Implementation
template< class _Type> _Type Binary_Multiplication( long long _a, long long _b, _Type _mod){
//<
// @Brief
// . @Return is `a * b (% mod)` and would in the range [0, mod);
// @TimeCost
// . $\log_2(b)$;
    ASSERT_( _mod >= 1 && _mod <= 9223372036854775807LL / 2);
    _Type ans = 0;
    _a %= _mod;  if( _a < 0){ _a += _mod;}
    _b %= _mod;  if( _b < 0){ _b += _mod;}
    if( _a < _b){ swap( _a, _b);}
    while( _b > 0){
        if( _b & 1){
            ans = (_a + ans) % _mod;
        }
        _a = (_a + _a) % _mod;
        _b >>= 1;
    }
    return ans;
}
//} Binary_Multiplication-Implementation
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值