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 }

 

posted @ 2020-03-10 18:02  zkw666  阅读(190)  评论(0编辑  收藏  举报