BZOJ 2476 战场的数目 矩阵乘法

题目大意:令战场定义为可以从中间某个点向两边单调不增且不是一个长方形的柱子的序列,求周长为p的柱子有多少个

令f[n]为周长为2n的战场数 不考虑【不是长方形】这个条件

如果一个战场左右都没有高度为1的柱子,则方案数等价于将最下方一排砍掉的方案数 即f[n-1]

如果一个战场左侧或右侧有一个高度为1的柱子,则方案数等价于砍掉这个高度为1的柱子的方案数 即2*f[n-1]

但是如果一个战场左侧和右侧都有一个高度为1的柱子,那么这个战场被上面那种情况计算了两次,要减掉 方案数是f[n-2]

故得到递推式f[n]=3*f[n-1]-f[n-2] 矩阵乘法搞出来 再减去长方形的方案数 即n-1即可

小心负号。。。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define MOD 987654321
using namespace std;
typedef long long ll;
struct Matrix{
	ll xx[2][2];
	Matrix(ll _=0,ll __=0,ll ___=0,ll ____=0)
	{
		xx[0][0]=_;
		xx[0][1]=__;
		xx[1][0]=___;
		xx[1][1]=____;
	}
	ll* operator [] (int x)
	{
		return xx[x];
	}
	friend void operator *= (Matrix &x,Matrix y)
	{
		int i,j,k;
		Matrix z;
		for(i=0;i<2;i++)
			for(j=0;j<2;j++)
				for(k=0;k<2;k++)
					z[i][j]+=x[i][k]*y[k][j],z[i][j]%=MOD;
		x=z;
	}
};
int n;
Matrix Quick_Power(Matrix x,int y)
{
	Matrix re(1,0,0,1);
	while(y)
	{
		if(y&1) re*=x;
		x*=x;y>>=1;
	}
	return re;
}
int Calculate(int n)
{
	if(n<=7) return 0;
	if(n&1) return 0;
	n>>=1;
	Matrix re=Quick_Power(Matrix(0,987654320,1,3),n-4);
	return (5*re[0][0]+13*re[1][0]-(n-1)%MOD+MOD)%MOD;
}
int main()
{
	while(cin>>n,n)
		cout<<Calculate(n)<<endl;
	return 0;
}


你可能感兴趣的:(矩阵乘法,bzoj,BZOJ2476)