这一题拿到手,第一感觉是不会太难,毕竟算是比较靠前的题目,呵呵。随手写了一个,也知道应该会挂掉,因为1 <= n <= 100,000,000,
#include <iostream>
using namespace std;
int main()
{
int a,b,n;
while(cin>>a>>b>>n && n)
{
int f1 = 1,f2 = 1,f,count = 3;
while(count <= n)
{
f = (a*f2 + b*f1)%7;
f1 = f2;
f2 = f;
count++;
}
cout<<f<<endl;
}
return 0;
}
不出意料地挂了,需要另寻他路。
暂时没有其他想法,第一反应是0<=f(n)<=6,而且一旦A、B的值给定,序列f(1)、f(2)、f(3)、…f(n)会出现循环。按照这个思路去试了一下题目给出的两个测试例子,果不其然,当(A,B)=(1,1)的时候,出现了循环,循环长度为16;当(A,B)=(1,2)时,也出现了循环,循环长度为12。
再进一步分析,观察给出的公式,
f(1) = 1, f(2) = 1, f(n) = (A * f(n - 1) + B * f(n - 2)) mod 7,
f(3)=(A+B)%7,
f(4)=(A*((A+B)%7)+B)%7,…,
f(n)=(A%7*f(n-1)+B%7*f(n-2))%7,
0<=A%7,B%7<=6,
所以循环的长度不会超过7*7=49.
循环的过程是这样的:
f = (a*f2 + b*f1)%7;
f1 = f2;
f2 = f;
也就是说到了某个阶段,会出现f(m-1) = f(n-1), f(m) = f(n),m<n
,不一定是从1,1开始循环的。所以思路很明显了,定义一个长度大于49的数组,对于确定的A、B,记录前面50次算出的结果,找出循环的部分即可。关键就是找到循环周期和循环的开始,一个比较笨的方法就是对于每次算出一个f(n),就比较f(n)和f(n-1)与之前算出的结果,如果能够找到一个m,m<n
,满足f(m-1) = f(n-1), f(m) = f(n)
,循环的周期自然就是n-m,对应的f(n)做一个映射就可以找到其值。
#include <iostream>
using namespace std;
int main()
{
int a,b,n,len,start;
while(cin>>a>>b>>n&&n)
{
int f[51]={-1};
f[1]=1,f[2]=1;
for(int i=3;i<51;i++)
{
f[i]=(a*f[i-1]+b*f[i-2])%7;
for(int j=2;j<i;j++)
{
if((f[j]==f[i])&&(f[j-1]==f[i-1]))
{
len=i-j;
start=j-1;
break;
}
}
}
if(n<start)
{
cout<<f[n]<<endl;
}
else
{
cout<<f[start+(n-start)%len]<<endl;
}
}
return 0;
}
当然还有其他解法,异曲同工。这篇博客写得比较详细
http://www.cnblogs.com/krisdy/archive/2009/04/12/1434013.html
版权声明:本文为博主原创文章,未经博主允许不得转载。
时间: 2024-12-24 02:04:03