数字游戏,如果硬说它有算法的话,那也只能说去找规律了。
初看本题的人,会觉得这这是一个简单的递归题目,其实我一开始也是这么想的,但后来提交了如下代码后我才明白。

#include <iostream>
using namespace std;
int main()
{
    int a,b,n;
    while(cin>>a>>b>>n && n)
    {
        int f1 = 1,f2 = 1,f,t = 3;
        while(t <= n)
        {
            f = (a*f2 + b*f1)%7;
            f1 = f2;
            f2 = f;
            ++t;
        }
        cout<<f<<endl;
    }
    return 0;
}

细细看下题目中的条件要求:1 <= n <= 100,000,000,你就应该明白本题绝不是简单的递归就可以解决的,上述代码的答案是TLE.(后来加):其实看到题目中出现求余运算,我就应该很快的反应过来,这道题目绝对不是简单的递归运算就可以解决问题的,因为求余运算会有一定的重复,所以,本题中的数据一定会出现重复,从重复中找到规律,问题就可以解决了。

其实解决本题的方法是找出规律,当f1,f2和a b的值确定后,你就可以利用题目中给出的公式往后计算了,如果我们把所有fn的取值算作一个队列(非数据结构中的队列)的话,可以肯定的是,这个队列不会延展太长,到了一定长度,肯定会出现重复,而我们需要做的就是找出这个重复点。
      什么时候会出现重复呢,如果我们假定队列是如下循环的:

f = (a*f2 + b*f1)%7;
f1 = f2;
f2 = f;

那么很简单就可以推出:当f1 = 1,且f2 = 1时就会出现队列一开始的循环了。此时我们就不需要继续向下递归了。不过我们需要把出现循环以前的所有值都保存下来。相比于时间复杂度来说,这点空间复杂度还是值得的。
这样写了代码,结果却Memory Limit Exceeded,郁闷,今天太晚了,明天再搞。

#include <iostream>
#include <vector>
using namespace std;
int main()
{
    int a,b,n;
    while(cin>>a>>b>>n && n)
    {
        vector<int> ivec;
        int f1 = 1,f2 = 1,f,t = 3,count,num;
        ivec.push_back(f1);
        ivec.push_back(f2);
        while(1)
        {
            f = (a*f2 + b*f1)%7;
            f1 = f2;
            f2 = f;
            if(f1 == 1 && f2 == 1)
                break;
            else
                ivec.push_back(f);
            ++t;
        }
        count = t - 2;
        num = n%count;
        if(num == 0)
            num = count;
        cout<<ivec.at(num - 1)<<endl;
        ivec.clear();
    }
    return 0;
}

昨天晚上找了杭电的WSN大牛问了下,一开始他也不是很清楚,只是让我把vector<int> ivec;设置为全局变量试下,这个我早已经试过,结果还是Memory limit Exceeded,问题应该不是出在这里,我初步猜测应该是有一组测试数据,让vector<int> ivec一直在执行push_back()操作,所以才会出现上述错误,看了WSN的AC代码后,他与我想法的区别在于数字的重复不一定是我所想的从头开始的重复,也可能是在中间部分开始重复的,举个简单的例子,这里没有理由依据:1 1 2 5 6 5 4 4 8 6 2 5 4....,如果是这样下去的话,从5 和 4开始就是重复了,并不是从开始的1 和1 开始重复的,这样也有道理。而且也实际上应该这么考虑才对。

后来,我随便试了几组数据,就发现出现了问题,当我输入21 56 45这组数据时,上面的程度没有输出,Debug后才知道,其实不是没有输出,而是程序在while(1)处进入了死循环,这样就导致我的ivec一直不间断的进行push_back()操作,才会有了开始的Memory Limit Exceeded这种错误。既然找到了错误,下面就剩下修改代码了,我决定采用WSN的想法,在判断是否开始重复时多加入一个条件判断,修改后AC,代码及注释如下:

#include <iostream>
#include <vector>
using namespace std;
vector<int> ivec;
//布尔数组元素flag[i][j]如果为true,则说明前面已经出现了i 和 j两者的组合
bool flag[7][7];
void init(void)
{
    int i,j;
    for(i = 0;i < 7;++i)
        for(j = 0;j< 7;++j)
            flag[i][j] = false;
}
int main()
{
    int a,b,n;
    while(cin>>a>>b>>n)
    {
        if(a == 0&&b == 0&&n == 0)
            break;
        ivec.clear();
        init();
        ivec.push_back(1);
        ivec.push_back(1);
        flag[1][1] = true;
        int count = 1,f;
        while(1)
        {
            f = (a*ivec.at(count)%7 + b*ivec.at(count - 1)%7)%7;
            ivec.push_back(f);
            ++count;
            //如果flag变量为true,则说明前面已经出现了这两者的组合,出现重复,无需下一步计算,直接break退出即可
            if(flag[ivec.at(count)][ivec.at(count - 1)] == true)
                break;
            else
                flag[ivec.at(count)][ivec.at(count - 1)] = true;
        }
        //count中存放的是ivec中出现循环前的元素总个数,注意ivec中的下标是从0开始计数的
        count = count - 1;
        if(n < count)
            cout<<ivec.at(n-1)<<endl;
        else
        {
            int j;
            //for循环的目的是找出从那个地方开始重复,此处应该是从j处开始循环,注意j是从0下标开始计数的
            for(j = 0;;++j)
                if(ivec.at(count) == ivec.at(j) && ivec.at(count + 1) == ivec.at(j+1))
                    break;
            n = (n - j)%(count - j);
            if(n == 0)
                n = count - j;
            n += j;
            cout<<ivec.at(n-1)<<endl;
        }
    }
    return 0;
}

后记:在我解决我这道题出现问题的过程中,我也在网上搜索了很多,找到了一些代码去测试,结果发现其实杭电服务器上关于本题的测试数据是不完整的,就拿我刚才那个测试数据来说:21 56  n来说,其循环应该为:
1 1 0 0 0 0 0 0 0 ...........,而我在网上找到的一些代码,比如下面这个代码:(来源:http://hi.baidu.com/chenghui2050/blog/item/84c552ad3124ee0f4a36d660.html)

#include<iostream>
using namespace std;
int main()
{
    int a,b,i;
    long long f[55],n;
    while(cin>>a>>b>>n)
    {
        if(a==0&&b==0&&n==0)break;
        f[1]=f[2]=1;
        for(i=3;i<=49;i++)
        f[i]=(a*f[i-1]+b*f[i-2])%7;
        cout<<f[n%48]<<endl;
    }
    return 0;
}

如果输入21 56 49时,正确输出应该是0,而上述代码却是1,明显是错误的,但却莫名的AC,希望看到的朋友们注意下。题目中并没有明确说明不会出现0 0这种情况,要注意。
按照WSN的思路考虑的话,应该是考虑比较全面的了,赞the lord of WSNs,呵呵.
这个问题先告一段落了,残酷的测试数据,倒。。。

转载于:https://www.cnblogs.com/krisdy/archive/2009/04/12/1434013.html

[HDOJ]1005. Number Sequence相关推荐

  1. HDU 1005 Number Sequence

    [题目]                                                   Number Sequence Time Limit: 2000/1000 MS (Jav ...

  2. HDU.1005 Number Sequence

    原题 HDU.1005 Number Sequence 分类 杂题 题意 给定一个数列{an}\left\{ a_n \right\}{an​}的前两项a1a_1a1​.a2a_2a2​,以及其递推公 ...

  3. 【HDU】1005 Number Sequence (有点可爱)

    http://acm.hdu.edu.cn/showproblem.php?pid=1005 A number sequence is defined as follows: f(1) = 1, f( ...

  4. [解题报告]1005 - Number Sequence

    题目大意 题目原文:http://acm.hdu.edu.cn/showproblem.php?pid=1005 背景: 问题描述: 编号规则定义如下: f(1) = 1,f(2) = 1,f(n) ...

  5. HDU 1005 — Number Sequence

    原题:http://acm.hdu.edu.cn/showproblem.php?pid=1005 思路: 找规律: 当出现两个1 时即找到了循环点:因为f[n]和f[n-1].f[n-2]有关,所以 ...

  6. HDU - 1005 Number Sequence(循环群)

    题目链接:点击查看 题目大意:给出递推公式以及模,求第n项 题目分析:这种裸的公式题,如果直接模拟实现,肯定不是超时就是爆内存,我们通过观察可以发现,无论a与b取何值,f[i]与f[i-1] 的关系始 ...

  7. 【HDOJ】1005 Number Sequence_天涯浪子_新浪博客

    [题目]http://acm.hdu.edu.cn/showproblem.php?pid=1005 [报告] 这道明显是数学题,但如果按位枚举显然是要TLE的. 仔细思考,它有一个MOD 7,这个很 ...

  8. HDU 1711 Number Sequence(KMP算法)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1711 Number Sequence Time Limit: 10000/5000 MS (Java/ ...

  9. 构造 HDOJ 5400 Arithmetic Sequence

    题目传送门 题意:问有多少个区间,其中存在j使得ai + d1 == ai+1(i<j) && ai + d2 == ai+1 (i>j) 构造:用c1[i], c2[i] ...

最新文章

  1. python中plot的plt.text_用Python进行数据可视化的第一步,全面详解matplotlib中样式属性...
  2. 人工智能到来的时代,你曾经瞧不起的职业,可能会非常吃香!
  3. 代码规范之eslint+prettier实践
  4. list中抽出某一个字段的值_使用LINQ获取List列表中的某个字段值
  5. css制作按钮按下去效果
  6. 单例设计模式之安全的懒汉式
  7. 汇编语言---乘法指令及符号扩展
  8. 步步为营-75-Cookie简介
  9. 小tips:JS语法之标签(label)
  10. python读写excel模块pandas_python3 基于pandas读写Excel
  11. 完全独立与IIS的后门
  12. HDU2050 由直线分割平面推广到折线分割平面
  13. PHP实现限制域名从而保护源代码不被拷贝
  14. vue for 初始值_vue全套教程(实操)就在这里
  15. 攻防世界-misc高手进阶篇-2017_Dating_in_Singapore
  16. java实现自行车行程
  17. 实现对光网络的监控和光路切换 - MEMS 光开关
  18. Excel图表—条形图的高级做法
  19. GRBL四:GRBL框架解析
  20. LinuxZIP压缩和解压缩

热门文章

  1. PHP笔记-双色球例子
  2. Qt文档阅读笔记-Q_GADGET官方解析及实例
  3. QML笔记-键盘事件中同时响应onDigitXXPressed与onPressed
  4. Spring Boot通过@RequestParam接收前端表单传来的数据
  5. Qt工作笔记-QMainWindow自定义窗体中利用状态栏进行窗体放缩
  6. WEB安全基础-PHP+MySQL实践
  7. DJS_130小型计算机,我收藏的中国第一台计算机djs-130的操作系统纸带
  8. oracle数据库要参考的书,[Oracle] 几本重要的电子图书下载-数据库专栏,ORACLE
  9. 高频面试题2:单例设计模式
  10. Linux系统编程30:进程信号之产生信号的四种方式(Core Dump,kill,raise)