zoukankan      html  css  js  c++  java
  • HDU 3306

    先转一些   http://www.cnblogs.com/frog112111/archive/2013/05/19/3087648.html

    Fibonacci数列:F(0)=1 , F(1)=1 , F(n)=F(n-1)+F(n-2)

    我们以前快速求Fibonacci数列第n项的方法是 构造常系数矩阵

    (一)   Fibonacci数列f[n]=f[n-1]+f[n-2],f[1]=f[2]=1的第n项快速求法(不考虑高精度)

    解法:

    考虑1×2的矩阵【f[n-2],f[n-1]】。根据Fibonacci数列的递推关系,我们可以通过乘以一个2×2的矩阵A,得到矩阵:【f[n-1],f[n]】。

    即:【f[n-2],f[n-1]】*A = 【f[n-1],f[n]】=【f[n-1],f[n-1]+f[n-2]】

    很容易构造出这个2×2矩阵A,即:
    0 1 
    1 1

    所以,有【f[1],f[2]】×A=【f[2],f[3]】
    又因为矩阵乘法满足结合律,故有:
    【f[1],f[2]】×A ^(n-1) =【f[n],f[n+1]】
    这个矩阵的第一个元素f[n]即为所求。

    (二)   数列f[n]=f[n-1]+f[n-2]+1,f[1]=f[2]=1的第n项的快速求法(不考虑高精度)

    解法:
    仿照前例,考虑1×3的矩阵【f[n-2],f[n-1],1】,希望求得某3×3的矩阵A,使得此1×3的矩阵乘以A得到矩阵:【f[n-1],f[n],1】

    即:【f[n-2],f[n-1],1】* A =【f[n-1],f[n],1】=【f[n-1],f[n-1]+f[n-2]+1,1】

    容易构造出这个3×3的矩阵A,即:
    0 1 0 
    1 1 0 
    0 1 1

    故:【f[1],f[2],1】* A^(n-1) = 【f[n],f[n+1],1】

    (三)数列f[n]=f[n-1]+f[n-2]+n+1,f[1]=f[2]=1的第n项的快速求法(不考虑高精度).
    解法:
    仿照前例,考虑1×4的矩阵【f[n-2],f[n-1],n,1】,希望求得某4×4的矩阵A,使得此1×4的矩阵乘以A得到矩阵:【f[n-1],f[n],n+1,1】
    即:【f[n-2],f[n-1],n,1】* A  = 【f[n-1],f[n],n+1,1】=【f[n-1],f[n-1]+f[n-2]+n+1,n+1,1】
    容易构造出这个4×4的矩阵A,即:
    0 1 0 0 
    1 1 0 0 
    0 1 1 0 
    0 1 1 1

    故:【f[1],f[2],3,1】* A^(n-1) = 【f[n],f[n+1],n+2,1】

    (四)   数列f[n]=f[n-1]+f[n-2],f[1]=f[2]=1的前n项和s[n]=f[1]+f[2]+……+f[n]的快速求法(不考虑高精度).

    解法:

    仿照之前的思路,考虑1×3的矩阵【f[n-2],f[n-1],s[n-2]】,我们希望通过乘以一个3×3的矩阵A,得到1×3的矩阵:【f[n-1],f[n],s[n-1]】
    即:【f[n-2],f[n-1],s[n-2]】 * A  = 【f[n-1],f[n],s[n-1]】=【f[n-1],f[n-1]+f[n-2],s[n-2]+f[n-1]】
    容易得到这个3×3的矩阵A是:
    0 1 0 
    1 1 1 
    0 0 1

    这种方法的矩阵规模是(r+1)*(r+1)

    f(1)=f(2)=s(1)=1 ,所以,有

    【f(1),f(2),s(1)】* A  = 【f(2),f(3),s(2)】

    故:【f(1),f(2),s(1)】* A^(n-1)  = 【f(n),f(n+1),s(n)】

    (五)   数列f[n]=f[n-1]+f[n-2]+n+1,f[1]=f[2]=1的前n项和s[n]=f[1]+f[2]+……+f[n]的快速求法(不考虑高精度).

    解法:

    考虑1×5的矩阵【f[n-2],f[n-1],s[n-2],n,1】,
    我们需要找到一个5×5的矩阵A,使得它乘以A得到如下1×5的矩阵【f[n-1],f[n],s[n-1],n+1,1】
    即:【f[n-2],f[n-1],s[n-2],n,1】* A  =【f[n-1],f[n],s[n-1],n+1,1】

    =【f[n-1], f[n-1]+f[n-2]+n+1,s[n-2]+f[n-1],n+1,1】
    容易构造出A为:
    0 1 0 0 0 
    1 1 1 0 0 
    0 0 1 0 0 
    0 1 0 1 0 
    0 1 0 1 1

    故:【f(1),f(2),s(1),3,1】* A^(n-1)  = 【f(n),f(n+1),s(n),n+2,1】

    一般地,如果有f[n]=p*f[n-1]+q*f[n-2]+r*n+s
    可以构造矩阵A为:
    0  q  0  0  0 
    1  p  1  0  0 
    0  0  1  0  0 
    0  r  0  1  0 
    0  s  0  1  1

    更一般的,对于f[n]=Sigma(a[n-i]*f[n-i])+Poly(n),其中0<i<=某常数c, Poly (n)表示n的多项式,我们依然可以构造类似的矩阵A来解决问题。
    设Degree(Poly(n))=d, 并规定Poly(n)=0时,d=-1,此时对应于常系数线性齐次递推关系。则本方法求前n项和的复杂度为:
    ((c+1)+(d+1))3*logns

    ---------------------------------------以上为转

    这样,这道题就不难解决了,决定好一个1X4的矩阵后,再按递推填一个4X4的就可以了。

    可以发现这个1X4的就是 (S(N-2),AN-2,AN-1,AN-1*AN-2)哈哈,自己推出来的,完美解决了。

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    
    using namespace std;
    
    struct Matrax {
    	int m[4][4];
    };
    int tms[4];
    Matrax a,per;
    int n=4,M=10007;
    int N,X,Y;
    void init(){
    	int i,j;
    	memset(per.m,0,sizeof(per.m));
    	memset(a.m,0,sizeof(a.m));
    	for(i=0;i<n;i++){
    		per.m[i][i]=1;
    	}
    	a.m[0][0]=a.m[2][0]=a.m[2][1]=1;
    	a.m[1][2]=((Y%M)*(Y%M))%M;; a.m[2][2]=((X%M)*(X%M))%M;
    	a.m[3][2]=(2*(X%M)*(Y%M))%M; a.m[2][3]=X%M; a.m[3][3]=Y%M;
    }
    
    
    Matrax multi(Matrax a,Matrax b){
    	Matrax c;
    	int k,i,j;
    	for(i=0;i<n;i++){
    		for(j=0;j<n;j++){
    			c.m[i][j]=0;
    			for(k=0;k<n;k++){
    				c.m[i][j]=(c.m[i][j]+(a.m[i][k]*b.m[k][j])%M)%M;
    			}
    		}
    	}
    	return c;
    }
    
    Matrax Power(int k){
    	Matrax c,p,ans=per;
    	p=a;
    	while(k){
    		if(k&1){
    			ans=multi(ans,p);
    			k--;
    		}
    		else{
    			k/=2;
    			p=multi(p,p);
    		}
    	}
    	return ans;
    }
    
    int main(){
    	while(scanf("%d%d%d",&N,&X,&Y)!=EOF){
    		init();
    	//	cout<<"No"<<endl;
    		if(N==0){
    			printf("1
    "); continue;
    		}
    		tms[0]=tms[1]=tms[2]=tms[3]=1;
    		Matrax t=Power(N);
    	//	cout<<"YES"<<endl;
    		int ans=0;
    		for(int i=0;i<4;i++)
    		ans=(ans+(tms[i]*t.m[i][0]))%M;
    		printf("%d
    ",ans);
    	}
    }
    

      

  • 相关阅读:
    新浪视频播放器站外调用代码
    豆瓣FLASHMP3播放器
    奇艺 代码
    优酷新版播放器站外调用代码详解
    优酷网视频播放器站外调用详解
    PHP数组的交集array_intersect(),array_intersect_assoc(),array_inter_key()函数的小问题
    给你的博客添加个看电影的频道
    fwrite(),fread()命令混用问题(有图有真相)
    PHP字符编码问题之GB2312 VS UTF8
    POJ 1637 Sightseeing tour
  • 原文地址:https://www.cnblogs.com/jie-dcai/p/3950052.html
Copyright © 2011-2022 走看看