P1939 矩阵加速(数列)
这个题若不看题目和范围,我首先想到用递推,不过 n≤2×10^9,若用递推,一定会超时。
要用矩阵加速的话首先要找到一个矩阵(不唯一),用来相乘;
〔a1,a2,a3〕是一个1×3的矩阵,我想把它转化为〔a2,a3,a4〕也是一个1×3的矩阵,所以要找的矩阵肯定是3×3的;
可以假设这个3×3的矩阵为 所以 a2=a1×a+a2×b+a3×c 所以a=0;b=1;c=0;同理可得d=0;e=0;f=1;
a4=a3+a1 所以 g=1;h=0;i=1;所以3×3的矩阵应为 可以看出若想得出an,则需要这个矩阵的(n-3)次方再乘
〔a1,a2,a3〕因为a1,a2,a3都为1,所以可以不用乘,最后得出〔a n-2,a n-1,a n〕;用 r[4][4]来存储乘完后的3×3矩阵,
则an就是 r[1][3]+r[2][3]+r[3][3];通过快速幂就能快速求出答案了。
其实这个题套用 P 3390 矩阵快速幂的代码就可以,所以我就不再解释了,关于矩阵如何快速幂的问题在上一篇博客(☜点他)已说明。
直接上完整代码:
1 #include<iostream> 2 using namespace std; 3 struct hls{ 4 long long s[4][4]; 5 }; 6 hls t,r; 7 long long k; 8 const long long m=1000000007; 9 hls operator * (const hls &a,const hls &b) 10 { 11 hls w; 12 for(int i=1;i<=3;++i) 13 { 14 for(int j=1;j<=3;++j) 15 { 16 w.s[i][j]=0; 17 } 18 } 19 for(int x=1;x<=3;++x) 20 { 21 for(int y=1;y<=3;++y) 22 { 23 for(int z=1;z<=3;++z) 24 { 25 w.s[x][y]+=(a.s[x][z]%m)*(b.s[z][y]%m); 26 w.s[x][y]%=m; 27 } 28 } 29 } 30 return w; 31 } 32 int main() 33 { 34 int q; 35 cin>>q; 36 while(q--) 37 { 38 cin>>k; 39 for(int i=1;i<=3;++i) 40 { 41 for(int j=1;j<=3;++j) 42 { 43 t.s[i][j]=0; 44 if(i!=j) r.s[i][j]=0; 45 else r.s[i][j]=1; 46 } 47 } 48 t.s[1][3]++; 49 t.s[2][1]++; 50 t.s[3][2]++; 51 t.s[3][3]++; 52 k=k-3; 53 while(k>0) 54 { 55 if(k%2==1) r=r*t; 56 t=t*t; 57 k/=2; 58 } 59 cout<<(r.s[1][3]+r.s[2][3]+r.s[3][3])%m<<endl; 60 } 61 return 0; 62 }