前沿:之前之做过一些递推关系式简单的矩阵快速幂,看了大牛的博客发现对于那种方程两边有多个不同的未知变量也可以用矩阵解决:http://blog.csdn.net/abcjennifer/article/details/5302198,于是找了几道题练手,顺便分享一下经验。
题目链接:http://acm.fzu.edu.cn/problem.php?pid=1683
思路:直接给出递推关系式:S(n)=S(n-1)+F(n)=S(n-1)+3*F(n-1)+2*F(n-2)+7*F(n-3).于是写成矩阵的形式:
从而求的S(n).
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 const int MOD=2009; 7 8 int n; 9 struct Matrix{ 10 int map[4][4]; 11 }Mata,Matb; 12 13 void Initiate() 14 { 15 for(int i=0;i<4;i++) 16 for(int j=0;j<4;j++) 17 Mata.map[i][j]=0; 18 Mata.map[0][0]=1,Mata.map[0][1]=3; 19 Mata.map[0][2]=2,Mata.map[0][3]=7; 20 21 Mata.map[1][1]=3,Mata.map[1][2]=2; 22 Mata.map[1][3]=7; 23 24 Mata.map[2][1]=Mata.map[3][2]=1; 25 } 26 27 28 Matrix Mul(const Matrix &a,const Matrix &b) 29 { 30 Matrix c; 31 for(int i=0;i<4;i++){ 32 for(int j=0;j<4;j++){ 33 c.map[i][j]=0; 34 for(int k=0;k<4;k++){ 35 c.map[i][j]+=a.map[i][k]*b.map[k][j]; 36 c.map[i][j]%=MOD; 37 } 38 } 39 } 40 return c; 41 } 42 43 Matrix Pow(Matrix &q,int n) 44 { 45 Matrix p; 46 for(int i=0;i<4;i++) 47 for(int j=0;j<4;j++) 48 p.map[i][j]=(i==j)?1:0; 49 while(n){ 50 if(n&1){ 51 p=Mul(p,q); 52 } 53 n>>=1; 54 q=Mul(q,q); 55 } 56 return p; 57 } 58 59 int main() 60 { 61 int _case,t=1; 62 scanf("%d",&_case); 63 while(_case--){ 64 scanf("%d",&n); 65 printf("Case %d: ",t++); 66 if(n==0)puts("1"); 67 else if(n==1)puts("4"); 68 else if(n==2)puts("9"); 69 else { 70 Initiate(); 71 Matb=Pow(Mata,n-2); 72 printf("%d\n",(Matb.map[0][0]*9+Matb.map[0][1]*5+Matb.map[0][2]*3+Matb.map[0][3]*1)%MOD); 73 } 74 } 75 return 0; 76 }
题目链接:http://acm.fzu.edu.cn/problem.php?pid=2117
思路:设a(n)表示n位数且7、9的出现的个数均为偶数的组数,b(n)表示7出现偶数次,9出现奇数次的组数,c(n)表示7出现奇数次,9出现偶数次的组数,d(n)表示7、9均出现奇数次的组数,于是有下列递推关系式:
a(n)=3*a(n-1)+b(n-1)+c(n-1);
b(n)=a(n-1)+3*b(n-1)+d(n-1);
c(n)=a(n-1)+3*c(n-1)+d(n-1);
d(n)=b(n-1)+c(n-1)+3*d(n-1);
于是可以构造矩阵:
[3,1,1,0] [a(n-1)] [a(n)]
[1,3,0,1] [b(n-1)] = [b(n]
[1,0,3,1] [c(n-1)] [c(n)]
[0,1,1,3] [d(n-1)] d[(n)]
从而矩阵快速幂求a(n)即可。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 const int MOD=1000000007; 7 8 long long n; 9 struct Matrix{ 10 long long map[4][4]; 11 }Mata,Matb; 12 13 14 void Initiate() 15 { 16 Mata.map[0][0]=3,Mata.map[0][1]=1; 17 Mata.map[0][2]=1,Mata.map[0][3]=0; 18 19 Mata.map[1][0]=1,Mata.map[1][1]=3; 20 Mata.map[1][2]=0,Mata.map[1][3]=1; 21 22 Mata.map[2][0]=1,Mata.map[2][1]=0; 23 Mata.map[2][2]=3,Mata.map[2][3]=1; 24 25 Mata.map[3][0]=0,Mata.map[3][1]=1; 26 Mata.map[3][2]=1,Mata.map[3][3]=3; 27 } 28 29 Matrix Mul(const Matrix &a,const Matrix &b) 30 { 31 Matrix c; 32 for(int i=0;i<4;i++){ 33 for(int j=0;j<4;j++){ 34 c.map[i][j]=0; 35 for(int k=0;k<4;k++){ 36 c.map[i][j]+=a.map[i][k]*b.map[k][j]; 37 c.map[i][j]%=MOD; 38 } 39 } 40 } 41 return c; 42 } 43 44 Matrix Pow(Matrix q,long long n) 45 { 46 Matrix p; 47 for(int i=0;i<4;i++) 48 for(int j=0;j<4;j++) 49 p.map[i][j]=(i==j)?1:0; 50 while(n){ 51 if(n&1){ 52 p=Mul(p,q); 53 } 54 n>>=1; 55 q=Mul(q,q); 56 } 57 return p; 58 } 59 60 61 int main() 62 { 63 Initiate(); 64 int _case; 65 scanf("%d",&_case); 66 while(_case--){ 67 scanf("%I64d",&n); 68 if(n==1)puts("3"); 69 else { 70 Matb=Pow(Mata,n-1); 71 // cout<<Matb.map[0][0]<<"**"<<Matb.map[0][1]<<"**"<<Matb.map[0][2]<<endl; 72 long long ans=(Matb.map[0][0]*3+Matb.map[0][1]*1+Matb.map[0][2]*1)%MOD; 73 printf("%I64d\n",ans); 74 } 75 } 76 return 0; 77 }
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3306
思路:这道题与前几道有所不同,辅助矩阵不定,不过也好办。
这里直接给出递推式:S(n)=S(n-1)+A(n)^2=S(n-1)+x^2*A(n-1)^2+y^2*A(n-2)^2+2*x*y*A(n-1)*A(n-2);
于是构造矩阵:
| S(n) | | 1 X^2 Y^2 2XY | | S(n-1) |
| A(n)^2 | = | 0 x^2 Y^2 2XY | | A(n-1)^2 |
| A(n-1)^2 | | 0 1 0 0 | | A(n-2)^2 |
| A(n)A(n-1) | | 0 X 0 Y | | A(n-1)A(n-2) |
于是就可以用矩阵快速幂求解S(n)了。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 #define MOD 10007 7 8 struct Matrix{ 9 int map[4][4]; 10 }Mata,Matb; 11 12 void Initiate(int x,int y) 13 { 14 for(int i=0;i<4;i++) 15 for(int j=0;j<4;j++) 16 Mata.map[i][j]=0; 17 Mata.map[0][0]=1,Mata.map[0][1]=(x*x)%MOD; 18 Mata.map[0][2]=(y*y)%MOD,Mata.map[0][3]=(2*x*y)%MOD; 19 20 Mata.map[1][1]=(x*x)%MOD;Mata.map[1][2]=(y*y)%MOD; 21 Mata.map[1][3]=(2*x*y)%MOD; 22 23 Mata.map[2][1]=1; 24 25 Mata.map[3][1]=x,Mata.map[3][3]=y; 26 } 27 28 Matrix Mul(const Matrix &a,const Matrix &b) 29 { 30 Matrix c; 31 for(int i=0;i<4;i++){ 32 for(int j=0;j<4;j++){ 33 c.map[i][j]=0; 34 for(int k=0;k<4;k++){ 35 c.map[i][j]+=a.map[i][k]*b.map[k][j]; 36 c.map[i][j]%=MOD; 37 } 38 } 39 } 40 return c; 41 } 42 43 Matrix Pow(Matrix q,int n) 44 { 45 Matrix p; 46 for(int i=0;i<4;i++) 47 for(int j=0;j<4;j++) 48 p.map[i][j]=(i==j)?1:0; 49 while(n){ 50 if(n&1){ 51 p=Mul(p,q); 52 } 53 n>>=1; 54 q=Mul(q,q); 55 } 56 return p; 57 } 58 59 int main() 60 { 61 int n,x,y,sum; 62 while(~scanf("%d%d%d",&n,&x,&y)){ 63 x%=MOD,y%=MOD; 64 if(n==2){ 65 sum=1+1+((x+y)%MOD*(x+y)%MOD)%MOD; 66 printf("%d\n",sum); 67 }else { 68 Initiate(x,y); 69 Matb=Pow(Mata,n-1); 70 // cout<<Matb.map[0][0]<<"**"<<Matb.map[0][1]<<"**"<<Matb.map[0][2]<<"**"<<Matb.map[0][3]<<endl; 71 sum=(2*Matb.map[0][0]+1*Matb.map[0][1]+1*Matb.map[0][2]+1*Matb.map[0][3])%MOD; 72 printf("%d\n",sum); 73 } 74 } 75 return 0; 76 }
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4686
思路:与上一题类似,直接给出递推式:S(n)=S(n-1)+F(n-1)*G(n-1)=S(n-1)+ax*bx*F(n-2)*G(n-2)+ax*by*F(n-2)+ay*bx*G(n-2)+ay*by。
于是构造矩阵:
[ 1,ax*bx,ax*by,ay*bx,ay*by] [ S(n-1) ] [ S(n) ]
[ 0,ax*bx,ax*by,ay*bx,ay*by] [ F(n-2)*G(n-2) ] [ F(n-1)*G(n-1) ]
[ 0, 0, ax, 0, ay] [ F(n-2) ] = [ F(n-1) ]
[ 0, 0, 0, bx, by] [ G(n-2) ] [ G(n-1) ]
[ 0, 0, 0, 0, 1] [ 1 ] [ 1 ]
从而矩阵快速幂求出S(n);
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 #define MOD 1000000007 7 typedef long long ll; 8 9 struct Matrix{ 10 ll map[5][5]; 11 }Mata,Matb; 12 13 void Initiate(ll ax,ll ay,ll bx,ll by) 14 { 15 for(int i=0;i<5;i++) 16 for(int j=0;j<5;j++) 17 Mata.map[i][j]=0; 18 Mata.map[0][0]=1,Mata.map[0][1]=ax*bx%MOD; 19 Mata.map[0][2]=ax*by%MOD,Mata.map[0][3]=ay*bx%MOD; 20 Mata.map[0][4]=ay*by%MOD; 21 22 Mata.map[1][1]=ax*bx%MOD,Mata.map[1][2]=ax*by%MOD; 23 Mata.map[1][3]=ay*bx%MOD,Mata.map[1][4]=ay*by%MOD; 24 25 Mata.map[2][2]=ax,Mata.map[2][4]=ay; 26 27 Mata.map[3][3]=bx,Mata.map[3][4]=by; 28 29 Mata.map[4][4]=1; 30 /* 31 for(int i=0;i<5;i++){ 32 for(int j=0;j<5;j++){ 33 cout<<Mata.map[i][j]<<" "; 34 } 35 cout<<endl; 36 }*/ 37 } 38 39 Matrix Mul(const Matrix &a,const Matrix &b) 40 { 41 Matrix c; 42 for(int i=0;i<5;i++){ 43 for(int j=0;j<5;j++){ 44 c.map[i][j]=0; 45 for(int k=0;k<5;k++){ 46 c.map[i][j]+=a.map[i][k]*b.map[k][j]; 47 c.map[i][j]%=MOD; 48 } 49 } 50 } 51 return c; 52 } 53 54 Matrix Pow(Matrix q,ll n) 55 { 56 Matrix p; 57 for(int i=0;i<5;i++) 58 for(int j=0;j<5;j++) 59 p.map[i][j]=(i==j)?1:0; 60 while(n){ 61 if(n&1){ 62 p=Mul(p,q); 63 } 64 n>>=1; 65 q=Mul(q,q); 66 } 67 return p; 68 } 69 70 71 int main() 72 { 73 // freopen("1.txt","r",stdin); 74 ll n,a0,ax,ay,b0,bx,by,sum,sum1; 75 while(~scanf("%I64d%I64d%I64d%I64d%I64d%I64d%I64d",&n,&a0,&ax,&ay,&b0,&bx,&by)){ 76 if(n==0)puts("0"); 77 else if(n==1){ 78 sum=(a0*b0)%MOD; 79 printf("%I64d\n",sum); 80 }else { 81 Initiate(ax,ay,bx,by); 82 Matb=Pow(Mata,n-1); 83 sum1=(a0*b0)%MOD; 84 // cout<<Matb.map[0][0]<<"**"<<Matb.map[0][1]<<"***"<<Matb.map[0][2]<<"***"<<Matb.map[0][3]<<"**"<<Matb.map[0][4]<<endl; 85 sum=(sum1*Matb.map[0][0]%MOD+(a0*b0%MOD)*Matb.map[0][1]%MOD+(a0*Matb.map[0][2]%MOD)+(b0*Matb.map[0][3]%MOD)+Matb.map[0][4])%MOD; 86 printf("%I64d\n",sum); 87 } 88 } 89 return 0; 90 }
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2971
思路:与上一道类似,直接给出递推式:S(n)=S(n-1)+F(n)^2=S(n-1)+4*x*x*F(n-1)^2-4*x*F(n-1)*F(n-2)+F(n-2)^2。
于是构造矩阵:
[1,4*x*x,-4*x,1] [S(n-1) ] [S(n) ]
[0,4*x*x,-4*x,1] [F(n-1)^2 ] = [F(n)^2 ]
[0, 2*x, -1, 0] [F(n-1)*F(n-2)] [F(n)*F(n-1)]
[0, 1, 0, 0] [F(n-2)^2 ] [F(n-1)^2 ]
从而矩阵快速幂求出S(n)。
PS:这里由于有负数出现,取模的时候得小心。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 typedef long long ll; 7 8 ll n,x,m,sum; 9 struct Matrix{ 10 ll map[4][4]; 11 }Mata,Matb; 12 13 void Initiate(ll x) 14 { 15 for(int i=0;i<4;i++) 16 for(int j=0;j<4;j++) 17 Mata.map[i][j]=0; 18 Mata.map[0][0]=1,Mata.map[0][1]=(4*x*x)%m; 19 Mata.map[0][2]=(m-4*x%m)%m,Mata.map[0][3]=1; 20 21 Mata.map[1][1]=4*x*x%m,Mata.map[1][2]=(m-4*x%m)%m;//处理负数 22 Mata.map[1][3]=1; 23 24 Mata.map[2][1]=2*x%m,Mata.map[2][2]=m-1;//处理负数 25 26 Mata.map[3][1]=1; 27 } 28 29 Matrix Mul(const Matrix &a,const Matrix &b) 30 { 31 Matrix c; 32 for(int i=0;i<4;i++){ 33 for(int j=0;j<4;j++){ 34 c.map[i][j]=0; 35 for(int k=0;k<4;k++){ 36 c.map[i][j]+=a.map[i][k]*b.map[k][j]; 37 if(c.map[i][j]>=m)c.map[i][j]%=m; 38 } 39 } 40 } 41 return c; 42 } 43 44 Matrix Pow(Matrix q,ll n) 45 { 46 Matrix p; 47 for(int i=0;i<4;i++) 48 for(int j=0;j<4;j++) 49 p.map[i][j]=(i==j)?1:0; 50 while(n){ 51 if(n&1){ 52 p=Mul(p,q); 53 } 54 n>>=1; 55 q=Mul(q,q); 56 } 57 return p; 58 } 59 60 int main() 61 { 62 // freopen("1.txt","r",stdin); 63 int _case; 64 scanf("%d",&_case); 65 while(_case--){ 66 scanf("%I64d%I64d%I64d",&x,&n,&m); 67 if(n==2){ 68 sum=(1*1+x*x)%m; 69 printf("%I64d\n",sum); 70 }else { 71 Initiate(x); 72 Matb=Pow(Mata,n-2); 73 // cout<<Matb.map[0][0]<<"**"<<Matb.map[0][1]<<"**"<<Matb.map[0][2]<<"***"<<Matb.map[0][3]<<endl; 74 sum=((((1+x*x)%m)*Matb.map[0][0])%m+((x*x%m)*Matb.map[0][1]%m)+(x*Matb.map[0][2])%m+Matb.map[0][3])%m; 75 printf("%I64d\n",sum); 76 } 77 } 78 return 0; 79 }
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3519
思路:令a(n)代表合法的个数,b(n)代表末两位不同,C(n)代表末两位相同。于是我们有如下递推关系式:
a(n)=2*a(n-1)+C(n-1);
b(n)=b(n-1)+C(n-1);
C(n)=b(n-1);
从而根据上式得出矩阵:
[2,0,1] [a(n-1)] [a(n)]
[0,1,1] [b(n-1)] = [b(n)]
[0,1,0] [C(n-1)] [C(n)]
从而矩阵快速幂求出a(n).
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 #define MOD 10007 7 8 struct Matrix{ 9 int map[3][3]; 10 }Mata,Matb; 11 12 Matrix Mul(const Matrix &a,const Matrix &b) 13 { 14 Matrix c; 15 for(int i=0;i<3;i++){ 16 for(int j=0;j<3;j++){ 17 c.map[i][j]=0; 18 for(int k=0;k<3;k++){ 19 c.map[i][j]+=(a.map[i][k]*b.map[k][j]); 20 c.map[i][j]%=MOD; 21 } 22 } 23 } 24 return c; 25 } 26 27 Matrix Pow(Matrix q,int n) 28 { 29 Matrix p; 30 for(int i=0;i<3;i++) 31 for(int j=0;j<3;j++) 32 p.map[i][j]=(i==j)?1:0; 33 while(n){ 34 if(n&1){ 35 p=Mul(p,q); 36 } 37 n>>=1; 38 q=Mul(q,q); 39 } 40 return p; 41 } 42 43 int main() 44 { 45 Mata.map[0][0]=2,Mata.map[0][2]=1; 46 Mata.map[1][1]=Mata.map[1][2]=1; 47 Mata.map[2][1]=1; 48 int n; 49 while(~scanf("%d",&n)){ 50 if(n<=2)puts("0"); 51 else { 52 Matb=Pow(Mata,n-2); 53 printf("%d\n",2*(Matb.map[0][1]+Matb.map[0][2])%MOD); 54 } 55 } 56 return 0; 57 }