poj3070

7 篇文章 0 订阅
2 篇文章 0 订阅

矩阵快速幂入门题

#include<iostream>
#include<cstdio>
using namespace std;
int n,a[2][2],b[2][2];
void mul(int a[2][2],int b[2][2],int ans[2][2])
{
     int t[2][2];
     for(int i=0;i<2;i++)
        for(int j=0;j<2;j++)
        {
                t[i][j]=0;
                for(int k=0;k<2;k++)
                t[i][j]=(t[i][j]+a[i][k]*b[k][j])%10000;
//就是矩阵相乘的公式(发现公式最内的循环就k变)
                }
     memcpy(ans,t,sizeof(t));
 }
int main()
{
	//cout<<sizeof(a)<<endl;
    while(scanf("%d",&n))
    {
        if(n==-1)return 0;
        a[0][0]=a[0][1]=a[1][0]=1;a[1][1]=0;
        b[0][0]=b[1][1]=1;
        b[1][0]=b[0][1]=0;
/*
F0 = 0, F1 = 1, and Fn = Fn ? 1 + Fn ? 2 for n ≥ 2. (where 0 ≤ n ≤ 1,000,000,000).
故用矩阵
[fn+1   fn] [1 1]^n
[fn   fn-1]=[1 0]  .要是题目不告诉我=这个... --神奇(★精华在这)
模拟一下就发现其实是有道理的每次乘以{(1,1)(1,0)}矩阵得到{(fn+1+fn,fn+1),(fn+1,fn)}发现每次向后移动了一个斐波那契数列
*/
        while(n)
        {
                if(n&1)mul(a,b,b);
                n>>=1;
                mul(a,a,a);
                } 
        printf("%d\n",b[1][0]);            
                              }
}
//腰好也不需要这样扭吧...开始还以为是什么-- (回溯思想--还联系到了奇偶性,不错的解法)
#include <iostream>
#include <string.h>
using namespace std;
int Fibonacci[2][2]={1,1,1,0};
void matrix_pow(int c[2][2],int n){
	//4进来4 2 1深入  1 2 (2*2)   4回溯
	//4进来5 2 1深入  1 2 (2*2+1) 5回溯
	//6进来6 3 1深入  1 3 (3*3)   6回溯
	int i,j,k;
	if(n == 1){
		memcpy(c,Fibonacci,4 * sizeof(int));   return;
	}
	int tmp[2][2];
	matrix_pow(tmp,n/2);
	for(i = 0;i < 2;i++)
		for(j = 0;j < 2;j++){
			c[i][j] = 0;
			for(k = 0;k < 2;k++)
				c[i][j] = (c[i][j] + tmp[i][k] * tmp[k][j]) % 10000;
		}	//tmp^2
	if(n & 1){		//指数为奇数
		memcpy(tmp,c,4 * sizeof(int)); //tmp=tmp^2
		for(i = 0;i < 2;i++)
			for(j = 0;j < 2;j++){
				c[i][j] = 0;
				for(k = 0;k < 2;k++)
					c[i][j] = (c[i][j] + tmp[i][k] * Fibonacci[k][j]) % 10000;
			}
	}
}
int main(){
	int n;
	while(cin>>n && n >= 0){
		if(n == 0){
			cout<<0<<endl;continue;
		}
		if(n == 1 || n == 2){
			cout<<1<<endl;	continue;
		}
		n-=2;//
		int c[2][2];
		matrix_pow(c,n);
		cout<<(c[0][0] + c[1][0]) % 10000<<endl;
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值