算法 {快速幂,快速乘}
快速幂
定义
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{ 为二次幂} k∈Z+,a∈Z,∑bi=k,bi 为二次幂;
比如
a
10
=
a
∗
a
∗
.
.
.
a^{10} = a*a*...
a10=a∗a∗...
.
因为
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 a∗b=a∗∑bi, 其中 ∑ 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