HDOJ 1005

题目大意:给出A,B,N三个参数根据公式f(n)=(A*f(n-1)+B*f(n-2))mod7计算f(n)?其中f(1)=1,f(2)=1,0<N<=100000000,0<A,B<1000.

算法思想:从题目中可以看出N很大,如果用一般方法肯定会超时,同时若设置规模为N的一维数组记录f[n]肯定会超内存,所以基于以上考虑采用滚动数组来解决内存问题,同时通过找出递推公式的规律来简化问题的规模。此处主要用到一些模数的性质(1)(a*b)%m=(a%m*b%m)%m (2) (a+b)%m=(a%m+b%m)%m;利用这两条性质可以将递推公式化简如下:f(n)=(A%7*f(n-1)+B%7*f(n-2)]%7,接下来对此公式进行分析:(引用http://acm.hdu.edu.cn/discuss/problem/post/reply.php?postid=10343&messageid=2&deep=1)

首先我记f[n]=g(f[n-1],f[n-2])
由于题目中脑残的%7
很显然这里对f[n]的值域A,有|A|<=48,其中由于初始值为1,1 显然要排除掉g(0,0)(不要问为什么,很显然。。)
接下来我们得到一个显而易见的结论,即f[n]必存在周期,且周期小于等于48

我用一个程序测试了一下,可能的周期解为
1,2,3,4,6,8,12,14,16,21,24,42,48
不要问为什么

事实上对于1,2,3,4,6,8,12,16,24,48  你们懂的
所以测试数据漏掉了什么情况?即14,21,42的情况 

正确的解法应该算出前96个解,然后找到最小正周期 利用周期函数的特性给出答案 
而不是针对测试数据的漏洞用脑残的方法解答 

最后吐槽下用循环数组竟然不能暴力解掉。。
----------------------------------------------------------------------------------
首先我不知道为什么说要排除掉g(0,0) 我没看到很显然的东西
题目中既然没有说a b不能是7的倍数,那么输入a=7 b= 7就是合法的,得到的序列就是 1 1 0 ...0 以后就都是g(0, 0)

周期小于等于48 这个我没算过,但是既然每个值都是在0-6之间,那么周期在49以内就是一定的,而出现0 0后,又一定是0 0循环下去,那么周期最大是48也是可以理解的
但是为什么要算96个解呢? 49个解已经足够了,出现第一个相同点,后面一定是相同的, 而最大周期是48,当算到49的时候,至少有一个是循环的了,这已经足够了

 
代码如下:

#include <iostream>
#include <cstdlib>
#include <cstring>
using namespace std;
int f[3];
int dp(int a,int b,int n)
{
  f[1]=1;
  f[2]=1;
  for(int i=3;i<=n%48;i++){
        f[0]=f[1];
        f[1]=f[2];
        f[2]=(a*f[1]+b*f[0])%7;     
  }
  return f[2];
}

int main(){
int a,b,n;
 while(cin>>a>>b>>n&&a!=0&&b!=0&&n!=0){
    cout<<dp(a,b,n)<<endl;
 }    
 return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值