快速幂取模:
原理:合并相同项,减少计算
计算(a^b)%c当b很大的时候用,朴素算法复杂度为n,快速幂复杂度为logn
以下为二进制优化后的代码:
ll quick_pow_mod(ll a,ll b,ll c)//二进制思想 二分乘 a^b=(a^2)^(b-1) 递推 { ll res=1;//乘法初始化为1 while(b) { if(b & 1)//判断b的二进制最后一位是否为1(&运算同为1则取1) { res=(res*a)%c;//每次乘都取一次模,防止数据溢出 如果二进制的b这一位上为1,更新res }// a=(a*a)%c;//b每移一位,更新一次a,相当于乘2 b=b>>1; } return res; }
快速幂有两个作用 一是降低复杂度,二是防止数据过大溢出。
同理,也有快速乘,但是我觉得这个玩意用的机会应该很少...
ll quick_mul(ll a,ll b,ll c)//类比快速幂 { ll res=0; while(b) { if(b&1) { res=(res+a)%c; } a=(a+a)%c; b=b>>1; } return res; }
矩阵快速幂取模:
矩阵乘法和快速幂的结合,可以快速计算矩阵a的n次幂,把快速幂中的乘法改成矩阵乘法就行。
ps:我就先默认矩阵为二阶方阵了,其他情况改成N就好。
扫描二维码关注公众号,回复:
919832 查看本文章
struct mat { ll a[2][2]; mat() { memset(a,0,sizeof(mat));//这一步不要忘记 } }; mat multiple(mat x,mat y)//模拟矩阵乘法,返回res矩阵 { mat res; for(int i=0;i<2;i++)//枚举res的行 { for(int j=0;j<2;j++)//枚举res的列 { for(int k=0;k<2;k++) { res.a[i][j]=((res.a[i][j]%mod)+((x.a[i][k]*y.a[k][j])%mod))%mod; } } } return res; } mat quick_pow(mat base,int n) { mat ans; for(int i=0;i<2;i++) { ans.a[i][i]=1;//初始化为单位矩阵 } while(n) { if(n&1) { ans=multiple(ans,base);//如果n这一位上为1,更新ans } base=multiple(base,base);//更新base n=n>>1; } return ans; }
应用:
如斐波拉切数列:已知f(n)=f(n-1)+f(n-2),由矩阵乘法可以通过中间矩阵,找到f(n)和已知项的关系
然后只要对转移矩阵快速幂就行了。
贴一道UVA-10689,斐波拉切数列的变形,给定前两项,求第n项对一个数取模,矩阵快速幂模版题
#include <iostream> #include <cmath> #include <algorithm> #include <cstring> typedef long long ll; using namespace std; int mod; int a,b,n,m;//第一项为a 第二项为b 求第n项的后m位 struct mat { ll a[2][2]; mat() { memset(a,0,sizeof(mat)); } }; mat multiple(mat x,mat y)//模拟矩阵乘法,返回值res仍为矩阵 { mat res; memset(res.a,0,sizeof(res.a)); for(int i=0;i<2;i++)//枚举行 { for(int j=0;j<2;j++)//枚举列 { for(int k=0;k<2;k++) { res.a[i][j]=((res.a[i][j]%mod)+((x.a[i][k]*y.a[k][j])%mod))%mod; } } } return res; } ll quick_power(int n) { mat base,res; base.a[0][0]=1; base.a[0][1]=1; base.a[1][0]=1; base.a[1][1]=0; //memset(res.a,0,sizeof(res.a)); for(int i=0;i<2;i++) { res.a[i][i]=1;//先初始化res矩阵为二维单位阵,类似于求乘积时初始化res为1 } while(n)//快速幂 { if(n&1) { res=multiple(res,base); } base=multiple(base,base); n=n>>1; } return (((res.a[0][0]*b)%mod+((res.a[0][1]*a)%mod))%mod); } int main() { int t; cin>>t; while(t--) { cin>>a>>b>>n>>m; mod=(int)pow(10,m); if(n!=0) { ll result = quick_power(n-1); cout << result << endl; } else cout<<a<<endl; } return 0; }
这种题最关键的还是构造矩阵,模版题ok,题目灵活了我大概率就gg了。
加油,数论第二步。