nyoj 1000 又见斐波那契数列

本文探讨了一个基于斐波那契数列的字符串生成问题,通过使用矩阵快速幂算法来高效计算大数值下的斐波那契数,并利用费马小定理解决了模运算的问题。文章还提供了一段C++实现代码。


<p><span style="font-size:18px;">分析:定义(x,y),x代表a的个数,y代表b的个数。</span></p>  <p><span style="font-size:18px;">           先找规律f(0)=a        (1,0)
  </span></p>  <p><span style="font-size:18px;">                          f(1)=b;       (0,1)
  </span></p>  <p><span style="font-size:18px;">                          f(2)=ab      (1,1)</span></p>  <p><span style="font-size:18px;">                          f(3)=abb     (1,2)</span></p>  <p><span style="font-size:18px;">                          f(4)=abbab   (2,3)</span></p>  <p><span style="font-size:18px;">                          f(5)=abbababb    (3,5)</span></p>  <p><span style="font-size:18px;">                          f(6)=abbababbabbab  (5,8)</span></p>  <p><span style="font-size:18px;">                          ......</span></p> <span style="font-size:18px;">由规律可知,f(n)=a^fibonacci(n-2)*b^fibonacci(n-1),但是n=500的时候fibonacci(500)
就已经超过1e100了,又因为求的数要%1000000007,而1000000007是素数,由费马小定理可
知:若p为素数,a^(p-1)≡1 (mod p)。a^b%p=(<span style="font-size:18px;">a^(k(p-1)+c)</span>)%p=(<span style="font-size:18px;">a^(k(p-1))*a^c</span>)%p=a^c%p
。所以f(n)=a^<span style="font-size:18px;">(<span style="font-size:18px;">fibonacci(n-2)%<span style="font-size:18px;">1000000006</span></span>)*b^(<span style="font-size:18px;">fibonacci(n-1)%<span style="font-size:18px;">1000000006</span></span>)%<span style="font-size:18px;">1000000007.</span></span></span>


#include <cstdio>

const int N = 1000000007;
struct mat{
	int n, m;
	long long a[12][12];
};
mat aa;

long long dfs(long long a, long long n)
{
	long long s;
	if(n == 1)return a;
	if(n%2)
	{
		s = dfs(a,n/2);
		return ( (s*s)%N )*a%N;
	}
	else
	{
		s = dfs(a,n/2);
		return s*s%N;
	}
}

mat mul(mat a,mat b)
{
	long long s;
	int i, j ,k;
	mat c;
	for ( i = 1; i <= 2; i++)
	{
		for ( j = 1; j <= 2; j++)
		{
			s = 0;
			for ( k = 1; k <= 2; k++)
			{
				s += (a.a[i][k] * b.a[j][k]) % (N-1);
			}
			c.a[i][j] = s;
		}
	}
	return c;
}

mat mul_mi(mat a,long long n)
{
	mat s;
	if(n == 1)return a;
	if(n%2)
	{
		s = mul_mi(a,n/2);
		return mul( mul(s,s), a);
	}
	else
	{
		s = mul_mi(a,n/2);
		return mul(s,s);
	}
}

int main()
{
	long long a, b, n, m, s1, s2, i, j, k;
	mat c;
	
	aa.a[1][1] = aa.a[1][2] = aa.a[2][1] = 1;
	aa.a[2][2] = 0;
	
	while(scanf("%lld%lld%lld",&a,&b,&n) != EOF)
	{
		if(n == 0)printf("%lld\n",a);
		if(n == 1)printf("%lld\n",b);
		if(n == 2)printf("%lld\n",a*b%N);
		if(n > 2)
		{
			c = mul_mi(aa,n-2);
			s1 = dfs(a,(c.a[2][1] + c.a[2][2]) %(N-1) );
			s2 = dfs(b,(c.a[1][1] + c.a[1][2]) %(N-1) );
			printf("%lld\n",s1*s2%N);
		}
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值