HDU3306 Another kind of Fibonacci 矩阵

时间:2023-02-07 12:15:19

欢迎访问~原文出处——博客园-zhouzhendong

去博客园看该题解


题目传送门 - HDU3306


题意概括

  A0=1,A1=1,AN=X*AN-1+Y*AN-2(N>=2).求SN,SN=A02+A12+…+An2.


题解

  这题是用矩阵做的,一看(sou)就知道。

  设si为前i项的答案。

  如果要求第i项的ai那么是很简单的。

  构建矩阵:

       ai-1       ai

  ai-2    0      y

  ai-1    1      x

  但是好像没用。

  没错,的确没用。

  我们从二次项考虑:

  si  =si-1+ai2

        =si-1+(xai-1+yai-2)2

     =si-1+x2ai-12+y2ai-22+2xyai-1ai-2

  那么对于ak2形式的已经可以完成递推了。但是有一个棘手的东西,就是akak-1怎么完成递推?

  我们继续推导:

  akak-1=(xak-1+yak-2)ak-1

      =xak-12+yak-1ak-2

  我们发现ak-12和ak-1ak-2这两个其实可以按照之前推出来的推,而且不影响后面的。

  于是,我们可以构建递推矩阵:

       si      ai2    ai-12    aiai-1

  si-1        1      0        0      0

  ai-12    x2     x2      1      x

  ai-22    x2     y2      0      0

  ai-1ai-2   2xy    2xy     0      y

  

  意义:

  si    = si-1+x2ai-12+y2ai-22+2xyai-1ai-2

  ai2  =        x2ai-12+y2ai-22+2xyai-1ai-2

  ai-1    =           ai-12

  aiai-1   =         xai-12+                yai-1ai-2

  

  那么原始矩阵的第一行就是

  s1   a12   a02   a1a0

  算出sn,就是把这个原始矩阵乘上n-1个递推矩阵。

  


代码

#include <cstring>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <cstdlib>
using namespace std;
const int mod=10007,m=4;
struct Mat{
int v[m][m];
Mat (){}
Mat (int x){
(*this).set(x);
}
void print(){
for (int i=0;i<m;i++,puts(""))
for (int j=0;j<m;j++)
printf("%5d ",v[i][j]);
puts("");
}
void set(int x){
memset(v,0,sizeof v);
if (x==1)
for (int i=0;i<m;i++)
v[i][i]=1;
}
Mat operator * (Mat x){
Mat ans(0);
for (int i=0;i<m;i++)
for (int j=0;j<m;j++)
for (int k=0;k<m;k++)
ans.v[i][j]=(ans.v[i][j]+v[i][k]*x.v[k][j])%mod;
return ans;
}
void operator *= (Mat x){
(*this)=(*this)*x;
}
}M,Md;
Mat MatPow(Mat x,int y){
Mat ans(1),now=x;
while (y){
if (y&1)
ans*=now;
now*=now;
y>>=1;
}
return ans;
}
int n,x,y;
int main(){
while (~scanf("%d%d%d",&n,&x,&y)){
x%=mod,y%=mod;
M.set(0);
int newi[m]={2,1,1,1};
int newd[m][m]={{1 ,0 ,0,0},
{x*x%mod ,x*x%mod ,1,x},
{y*y%mod ,y*y%mod ,0,0},
{2*x*y%mod ,2*x*y%mod ,0,y}};
memcpy(M.v[0],newi,sizeof newi);
memcpy(Md.v,newd,sizeof newd);
Md=MatPow(Md,n-1);
M*=Md;
printf("%d\n",M.v[0][0]);
}
return 0;
}