现在的位置: 首页 > 综合 > 正文

矩阵入门 hdu 3519 lucky coins sequence

2019年09月02日 ⁄ 综合 ⁄ 共 1215字 ⁄ 字号 评论关闭

数学题目。

设数列a[ i ]表示第 i 个位置的正反情况。并以1表示向上,0表示向下。

从反面考虑,即求最长相连的同值a[]数不超过2时,(a)的个数,设之为p[n];

假设a[1]=x,进行分类:

1) a[2]=!x;

 有p[n-1]种序列。即对a[2]值的指派不会减少2到n的子(a)个数。

乍看之下这是奇怪的,但仅仅需要认识到以下几点,结论便是显然的。

a.!x的指派是两种而非一种。

b.由于a[1]与a[2]指派不同,在问题的结果中间,任意的从2到n的子(a),在本身合法的条件下,构成的(a)也合法。

2) a[2]=x;

那么,显然的,a[3]=!x;利用(1)中的结论,有p[n-2]种序列(a)。

那么p[n]=p[n-1]+p[n-2];

另外p[1]=2,p[2]=4,故,根据p[]的递推公式,形式上的拓展p[]的定义,使p[0]=2,p[-1]=0;

那么显然的,p[n]=2×f[n+1] (f[n]表示斐波那契数列)。

问题的解就是ans=2^n-2×f[n+1];(n>=3)

ans=0(n<3)

另外,代码的##处利用费马小定理减小了数据规模,节省了时间。不过就本题而言,这个优化也许不是必要的。

#include<stdio.h>
#define M 10007

int numqpow(int a,int k)
{
	int ans=1;
	while(k)
	{
		if(k&1)ans*=a;
		k>>=1;
		a*=a;
		ans%=M;
		a%=M;
	}
	return ans;
}

struct mat
{
	int x[3][3];
}m0;//step=2
mat mul(mat a,mat b)
{
	mat c;
	for(int i=1;i<=2;i++)
	{
		for(int j=1;j<=2;j++)
		{
			c.x[i][j]=0;
			for(int k=1;k<=2;k++)
			{
				c.x[i][j]+=a.x[i][k]*b.x[k][j];
				c.x[i][j]%=M;
			}
		}
	}
	return c;
}
mat matqpow(mat a,int k)
{
	mat c=a;
	k--;
	while(k)
	{
		if(k&1)c=mul(c,a);
		k>>=1;
		a=mul(a,a);
	}
	return c;
}
void init()
{
	m0.x[1][1]=1;
	m0.x[1][2]=1;
	m0.x[2][1]=1;
	m0.x[2][2]=0;
}

int fib(int n)
{
	mat ans=matqpow(m0,n);
	return ans.x[1][2];
}
int main()
{
	int n;
	while(scanf("%d",&n)==1)
	{
		if(n<3)
		{
			printf("0\n");
			continue;
		}
		init();
		int ans=0-2*fib(n+1);
		//printf("%d\n",ans);
		n%=(M-1);//##
		ans+=numqpow(2,n);
		while(ans<0)ans+=M;
		ans%=M;
		printf("%d\n",ans);
	}
	return 0;
}

抱歉!评论已关闭.