快速幂
将幂进行二进制化
分解成1次2次4次的形式
比如2的5次
将5变成二进制形式101
过程表示为2的1次乘2的4次
每次循环只要将2进行平方
在幂对1与运算后若为1则运算,否则就跳过此次运算
这样就能使整个计算过程的时间复杂度缩减为logn
ll ksm(ll a,ll b,ll m){
ll ans=1;
while(b){
if(b&1)
ans*=a;
ans%=m;
a*=a;
a%=m;
b>>=1;
}
return ans%=m;
}
高精度快速幂
在原有的快速幂模版下
将乘法改为高精度乘法就能达成
这里用了一个辅助数组在乘法中
在ksm开始时因为先使底数为1,所以在计算结束后要减去1
别忘了判断最后一位是否为非负数
int res[N],q[N];
void mul(int a[],int b[]){
int C[N];
memset(C,0,sizeof(C));
for(int i=1;i<=500;i++)
{
for(int j=1;j<=500;j++)
{
if(i+j-1>500)continue;
C[i+j-1]+=a[i]*b[j];
C[i+j]+=C[i+j-1]/10;
C[i+j-1]%=10;
}
}
for(int i=1;i<=500;i++)
a[i]=C[i];
}
void gjd_ksm(int p){
res[1]=1;
q[1]=2;//底数
while(p){
if(p&1){
mul(res,q);
}
mul(q,q);
p>>=1;
}
res[1]--;
int t=1;
while(res[t]<0)
{
res[t+1]--;
res[t]+=10;
t++;
}
}
矩阵快速幂
同样套用ksm模版
在进行矩阵乘法时,可以使用函数重载来使代码简便
ll n,k;
struct demo{
ll q[N][N];
demo(){
memset(q,0,sizeof q);
}
}res,e;
demo operator*(demo a,demo b){
demo t;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
for(int k=1;k<=n;k++){
t.q[i][j]+=(a.q[i][k]*b.q[k][j])%MOD;
t.q[i][j]%=MOD;
}
}
}
return t;
}
void ksm(){
for(int i=1;i<=n;i++){
res.q[i][i]=1;
}
while(k){
if(k&1){
res=res*e;
}
e=e*e;
k>>=1;
}
}
void solve(){
cin >> n >> k;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cin >> e.q[i][j];
}
}
ksm();
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cout << res.q[i][j] <<' ';
}
cout << endl;
}
}
矩阵加速
在某些给出类似斐波那契的递归函数题型时,可以使用矩阵加速
需要初始的前几位值组成基矩阵
再创建一个加速矩阵最为需要乘的转换方程
意为基矩阵乘上几次加速矩阵便能得出第几个值
ll n,m;
struct demo{
ll q[4][4];
demo(){
memset(q,0,sizeof q);
}
}res,e;
demo operator*(demo a,demo b){
demo t;
for(int i=1;i<=3;i++){
for(int j=1;j<=3;j++){
for(int k=1;k<=3;k++){
t.q[i][j]+=(a.q[i][k]*b.q[k][j])%MOD;
t.q[i][j]%=MOD;
}
}
}
return t;
}
void ksm(){
memset(e.q,0,sizeof e.q);
memset(res.q,0,sizeof res.q);
res.q[1][1]=res.q[1][2]=res.q[1][3]=1;
e.q[1][1]=e.q[2][3]=e.q[1][2]=e.q[3][1]=1;
n-=3;
while(n){
if(n&1){
res=res*e;
}
e=e*e;
n>>=1;
}
}
void solve(){
cin >> n;
if(n<=3){
cout << 1 << endl;
}else{
ksm();
cout << res.q[1][1] << endl;
}
}