HDU3306 Another kind of Fibonacci 矩阵

欢迎访问~原文出处——博客园-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-12ak-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-12    =           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;
}

  

posted @ 2017-11-07 21:21  zzd233  阅读(266)  评论(0编辑  收藏  举报