HDOJ1005
题目
Problem Description
A number sequence is defined as follows:
f(1) = 1, f(2) = 1, f(n) = (A * f(n - 1) + B * f(n - 2)) mod 7.
Given A, B, and n, you are to calculate the value of f(n).
Input
The input consists of multiple test cases. Each test case contains 3 integers A, B and n on a single line (1 <= A, B <= 1000, 1 <= n <= 100,000,000). Three zeros signal the end of input and this test case is not to be processed.
Output
For each test case, print the value of f(n) on a single line.
Sample Input
1 1 3
1 2 10
0 0 0
Sample Output
2
5
思路
1.这道题有点像斐波那契数列,所以我的第一想法是用递归。程序写好后,测试数据是可以过的,但是OJ下会显示Memory Limit Exceeded,内存超限了。原因是1 <= n <= 100,000,000,当n的值很大时,递归很深。
2.后来去CSDN上看别人的代码,发现递归时调用f(n%49)就可以AC了。但是这实际是错误的代码。 随便找一个例子试一下就可以验证它是错误的,比如下面的:
A=7, B=7
n f(n)
1 1
2 1
3 0
4 0
5 0
...
当n的值为51时,用f(n%49)算出来的值是1,正确答案是0。所以能AC,说明这一题的测试数据比较水,不够严谨。
3.之后又换了个方法。利用式子本身的特点,f(n) = (A * f(n - 1) + B * f(n - 2)) mod 7 = (A * f(n - 1) %7+ B * f(n - 2)%7) mod 7 。给定A,B后,A,B的值就确定了。f(n)的值是由前两个值决定的,即由f(n-1)和f(n-2)决定,所以当出现f(m-1) = f(n-1), f(m) = f(n)时,就出现了循环。f(n - 1) %7和f(n - 2)%7的值在0到6之间,所以两两组合的话有49种可能,也就是说循环长度最多是49。可以把f(3), f(4), f(5)…的数据依次算出来存放在一个数组中,直到出现循环点count为止,最后调用f(n%count)。下面是主要的代码:
for(i=3;i<51;i++)
{
number[i] = (A*number[i-1] + B*number[i-2])%7;
//printf("%d ", number[i]);
if(number[i]==1&&number[i-1]==1) //出现循环点后break
{
break;
}
}
count = i-2; //真正的循环长度为i-2
//n对count取余只会出现0到count-1的数,所以把number[count]的结果存放在number[0]中
number[0] = number[count];
printf("%d\n", number[n%count]);
不过还是要强调一下,代码依然是错误的.
验证的例子同上。
4.终极想法:把A,B分情况考虑。
A%7!=0&&A%7!=1&&B%7==0
if(A%7!=0&&A%7!=1&&B%7==0)
{
for(i=2;i<51;i++)
{
number[i] = (A*number[i-1])%7;
//printf("%d ", number[i]);
if(number[i]==1)
{
break;
}
}
count = i-1; //相当于把原来的结果往前移动一个,那么从f(1)开始循环
// printf("count = %d\n", count);
number[0] = number[count];
if(n==1)
{
printf("1\n"); //因为把原来的f(1)忽略了,所以单独输出
}
else
{
printf("%d\n", number[(n-1)%count]);
}
}
举个例子:
A = 2, B = 7
n 1 2 3 4 5 6 7 8 9 10
f(n) 1 1 2 4 1 2 4 1 2 4
f(n0) 1 2 4 1 2 4 1 2 4 1
把结果往前移动一个,忽略原来的f(1),并将其单独输出
A%7== 0 && B%7!=0:
//和最后一种情况一样
A%7== 0 && B%7== 0:
else if(A%7==0&&B%7==0)
{
if(n==1||n==2)
{
printf("1\n");
}
else
{
printf("0\n");
}
}
A%7!=0&&B%7!=0:
else
{
for(i=3;i<51;i++)
{
number[i] = (A*number[i-1] + B*number[i-2])%7;
//printf("%d ", number[i]);
if(number[i]==1&&number[i-1]==1)
{
break;
}
}
count = i-2;
// printf("count = %d\n", count);
number[0] = number[count];
printf("%d\n", number[n%count]);
}
Conclusion
在写这篇博客的时候,即使我的思路是正确的,但代码还没有AC。后来博客写着写着,多试了几个例子,就发现了原来代码的问题。经过改正后,也成功AC了。本篇博客主要是揭示了CSDN上很多主流hdoj1005题解法的错误。如果有更简单的解法,也欢迎在评论留言。就酱~