POJ 3734 Blocks 生成函数及矩阵的解法

http://poj.org/problem?id=3734

无意中看到这题然后网上看了题解,正好可以用生成函数解决,也看到有用矩阵解决的,所以学习了用两种方法解决该问题。网上也有很多人建议用费马定理的,这里就不一一实现。

(1)用生成函数推出其公式,同斐波那契的通项式类似,推出其规律,然后编程就很容易。 

#include <iostream>
const int MOD = 10007;

int tmod_n(int x, int n){
	int ans = 1;
	while(n > 0){
		if(n%2 == 1){
			ans = ans*x%MOD;
		}
		x = x*x%MOD;
		n /= 2;
	}
	return ans;
}

int getAns(int k){
	if(0 == k){
		return 0;
	}
	if(1 == k){
		return 2;
	}
	int ans = tmod_n(4, k-1) + tmod_n(2, k-1);
	ans %= MOD;
	return ans;
}

int main()
{
	int t = 0;
	std::cin>>t;
	while(t--){
		int x;
		std::cin>>x;
		std::cout<<getAns(x)<<std::endl;
	}
	
	return 0;
}

(2)找出其关系式,不用推其通项式,直接用矩阵实现,发现这样推的过程少很多,当然程序效率与上述相比也差很多,但我觉的矩阵给我们提供了一种很好解决问题的思路。下面的代码没经过仔细推敲,主要是学习式的应用一些知识。

//poj 3734 矩阵实现
//ans[i+1] = ans[i]*2 + 2*4^(i-2); i > 2

#include <iostream>
const int MOD = 10007;

class Matrix{
public:
	Matrix(int r, int c);
	Matrix(const Matrix& m);
	Matrix& operator=(const Matrix&);
	~Matrix();
public:
	int row, cross;
	int** mat;
};

inline Matrix::Matrix(int r, int c)
:row(r), cross(c){
	mat = new int*[r];
	for(int i = 0; i < r; i++){
		mat[i] = new int[c];
	}
}

Matrix::Matrix(const Matrix& m){
	row = m.row;
	cross = m.cross;
	mat = new int*[row];
	int r, c;
	for(r = 0; r < row; r++){
		mat[r] = new int[cross];
		for(c = 0; c < cross; c++){
			mat[r][c] = m.mat[r][c];
		}
	}
}

Matrix& Matrix::operator =(const Matrix& m){
	if(this == &m){
		return *this;
	}
	int r, c;
	for(r = 0; r < row; r++){
		delete []mat[r];
	}

	row = m.row;
	cross = m.cross;
	for(r = 0; r < row; r++){
		mat[r] = new int[cross];
		for(c = 0; c < cross; c++){
			mat[r][c] = m.mat[r][c];
		}
	}
	return *this;
}

Matrix::~Matrix(){
	int r;
	for(r = 0; r < row; r++){
		delete []mat[r];
	}
}

Matrix multMatrix(Matrix& mx, Matrix& my){
	if(mx.cross != my.row){
		Matrix mtmp(0, 0);
		return mtmp;
	}
	Matrix tmp(mx.row, my.cross);
	int r, c, t;
	for(r = 0; r < tmp.row; r++){
		for(c = 0; c < tmp.cross; c++){
			tmp.mat[r][c] = 0;
			for(t = 0; t < mx.cross; t++){
				tmp.mat[r][c] += mx.mat[r][t]*my.mat[t][c];
			}
			tmp.mat[r][c] %= MOD;  ///=========
		}
	}
	return tmp;
}

int modMatrix(int n, Matrix m, int val)
{
	Matrix orl(2, 1);
	orl.mat[0][0] = val; orl.mat[1][0] = 2;
	Matrix tmp(2, 2);
	tmp.mat[0][0] = 1; tmp.mat[0][1] = 0;
	tmp.mat[1][0] = 0; tmp.mat[1][1] = 1;
	while(n > 0){
		if(n%2==1){
			tmp = multMatrix(tmp, m);
		}
		m = multMatrix(m, m);
		n /= 2;
	}
	orl = multMatrix(tmp, orl);
	return orl.mat[0][0];
}

int getAns(int n){
	if(0 == n) return 0;
	if(1 == n) return 2;

	Matrix m(2, 2);
	m.mat[0][0] = 2; m.mat[0][1] = 1;
	m.mat[1][0] = 0; m.mat[1][1] = 4;
	return modMatrix(n-1, m, 2)%MOD;
}

int main()
{
	int t;
	std::cin>>t;
	while(t--){
		int n;
		std::cin>>n;
		std::cout<<getAns(n)<<std::endl;
	}
	return 0;
}

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值