HDOJ1005 Number Sequence

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题解法的错误。如果有更简单的解法,也欢迎在评论留言。就酱~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值