[NOI2013]矩阵游戏
做题时间:2022.7.4
给定正整数 ,有一个 行 列( )的矩阵 ,满足:
求 的值。
一行
一行一个数表示
矩阵快速幂,欧拉函数
看数据范围可知要使用矩阵快速幂,同时递推式表明用第二个式子确定好当前行第1列的数字后,第m列的数字即可用第一个式子套矩阵快速幂快速求出,而下一行第1列的数字又和这一行第m列有关, 因此可以考虑将两个式子合并 。
- 第一个式子:
就有:
这里我们发现,不能直接求出的 可以用第二个式子带入。
- 第二个式子:
就有:
这里我们发现,第一个式子中不能直接求出的 可以用第二个式子带入,得到:
这个式子中不能直接求出的 又可以带回第一个式子,得到:
直接用矩阵快速幂即可。
对于输入而言,根据欧拉定理:
我们用字符串读入 ,然后直接对 取余即可。
注意 :在 时,原来作为底数的矩阵主对角线均为1,相当于数字1,此时欧拉定理不适用,不能模 而应当模
#include<cstdio> #include<cstring> #include<iomanip> using namespace std; typedef long long ll; const ll phi=1e9+6,N=1e6+50,MOD=1e9+7; struct Matrix{ ll a[3][3]; Matrix(){memset(a,0,sizeof(a));} Matrix operator *(const Matrix x){ Matrix ans; for(int i=1;i<=2;i++){ for(int j=1;j<=2;j++){ for(int k=1;k<=2;k++){ ans.a[i][j]=(ans.a[i][j]+a[i][k]*x.a[k][j]%MOD)%MOD; } } } return ans; } }A1,A2,A3; char nn[N],mm[N]; ll a,b,c,d,n,m; void Pre()//字符串转化为数字 { int lenn=strlen(nn+1); int lenm=strlen(mm+1); ll pow=1; for(int i=lenn;i>=1;i--){ n=(n+pow*(nn[i]-48)); pow*=10; if(a==1) n%=MOD,pow%=MOD;//特判底数矩阵为1的情况 else n%=phi,pow%=phi; } pow=1; for(int i=lenm;i>=1;i--){ m=(m+pow*(mm[i]-48)); pow*=10; if(a==1) m%=MOD,pow%=MOD; else m%=phi,pow%=phi; } } Matrix FastPow(Matrix x,ll b)//矩阵快速幂 { Matrix ans; ans.a[1][1]=ans.a[2][2]=1; while(b){ if(b&1) ans=ans*x; x=x*x; b>>=1; } return ans; } int main() { scanf("%s%s",nn+1,mm+1); scanf("%lld%lld%lld%lld",&a,&b,&c,&d); Pre(); A1.a[1][1]=A1.a[1][2]=1; A2.a[1][1]=a,A2.a[1][2]=0,A2.a[2][1]=b,A2.a[2][2]=1; A3.a[1][1]=c,A3.a[1][2]=0,A3.a[2][1]=d,A3.a[2][2]=1; //赋初值 Matrix x=FastPow(A2,(2*m-1)%phi); Matrix tmp=FastPow(A2,(m-1)%phi)*A3; Matrix ans=A1*FastPow(tmp,(n-1)%phi)*FastPow(A2,(m-1)%phi); printf("%lld\n",ans.a[1][1]%MOD); return 0; }
本文作者:lxzy
本文链接:https://www.cnblogs.com/Unlimited-Chan/p/16448266.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步