从HD OJ 1005想到的
杭电OJ [1005](http://acm.hdu.edu.cn/showproblem.php?pid=1005): #####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 题目对于那些ACM选手来说,肯定不是什么大问题,不过对于我们这种只能刷刷水题的人来说,还是有点困难的。 我看到题目之后的第一反应是对于每一个特定的A和B,每次的计算结果都存到数组里,这样不用每个输入都重新计算,可以节省一定量的时间,当时觉得这个想法已经不错了,但是还是TLE了。最后上网找了答案,发现很多答案里都提到f(n)的值其实是循环的,而且最大的循环长度不会超过49(即起码在n=49之前,f(n)的值就开始循环了,f(k)=f(1),f(k+1)=f(2),f(k+2)=f(3),...,k<=49)。但是网上很多文章并没有指出怎么才能发现,或者说推导出这个规律。最后我花了点时间,自己推了下才终于知道了发现规律的方法。 首先,观察到递推式里有mod 7,就知道f(n)的所有值都在[0, 6]之间,有7个取值。 然后,观察递推式,f(n) = (A * f(n - 1) + B * f(n - 2)) mod 7,A和B是定常数,而f(n - 1)和f(n - 2)的取值都分别有7种可能,也就是说f(n)的取值最多有49种组合(这49种组合中,和可能相同,但是代表的意义不同,例如1+4和2+3是不同的,2+3和3+2也是不同的)。当n > 51时(因为这种组合是从n=3开始算的),f(n)的取值组合必然是之前出现过了的,也就是必存在
```
f(n) = f(k), f(n - 1) + f(n - 2) = f(k - 1) + f(k - 2)
f(n - 1) = f(k - 1)
f(n - 2) = f(k - 2)
```
但是其实我们可以知道,f(n) = 0 + 0,这种情况是不可能的(因为这样话很容易证明对于所有的n,f(n)都是为0),所以其实最多只有48种情况,即从n = 50开始,组合就必然出现重复了。
其次,我们知道了f(n)和f(k)的取值组合完全相同后,只要证明f(n + 1) = f(k + 1)的即可证明f(n)的取值在n > 49后必然存在循环。
```
f(n + 1) = f(n) + f(n - 1)
f(n) = f(k)
f(n - 1) = f(k - 1)
```
由以上条件可知,f(n + 1) = f(k + 1),同理可以推导出f(n + 2) = f(k + 2),...,等等。并最终证明f(n)的值是循环的。 最后,我们已经证明了f(n)是存在循环的,最后要证明的是f(n)是整循环的,也就是说循环起始点应该是f(n) = f(n - 1) + f(n - 2) = f(1) + f(2)。先假设f(n + 2) = f(5) = f(n + 1) + f(n) = f(4) + f(3),n是循环开始点,由假设可以推导出f(n + 1) = f(n) + f(n - 1) = f(4) + f(3),f(n - 1)和f(3)之前存在两种可能:
1. f(n - 1) = f(3)
2. |f(n - 1) - f(3)| = 7
由f(n)的取值范围[0, 6]知,第二种情况是不可能的,所以f(n - 1) = f(3),所以n - 1是循环开始点,依次可以类推n - 2是循环开始点,...,直到f(n - k) = f(3) = f(n - k - 1) + f(n - k - 2) = f(2) + f(1),n - k - 2是循环开始点。所以由证明可知,如果n是循环开始点,则f(n) = f(1),f(n + 1) = f(2),...。 知道了f(n)的值是循环的之后,这道题目就很容易做了,只要求出循环开始点就行了,即f(i - 1) = 1, f(i) = 1。 具体实现代码如下:
#include <iostream>
using namespace std; int f[50] = {0, 1, 1};
int a, b, n;
int main() {
while (cin >> a >> b >> n) {
if (a == 0 && b == 0 && n == 0) {
break;
}
if (n > 2) {
int i;
for (i = 3; i <= 49; i++) {
f[i] = (a * f[i - 1] + b * f[i - 2]) % 7;
if (f[i] == f[2] && f[i - 1] == f[1]) {
break;
}
}
i -= 2;
n = n % i == 0 ? i : n % i;
}
cout << f[n] << endl;
}
}
从HD OJ 1005想到的的更多相关文章
- (light OJ 1005) Rooks dp
http://www.lightoj.com/volume_showproblem.php?problem=1005 PDF (English) Statistics Forum Tim ...
- Light oj 1005 - Rooks (找规律)
题目链接:http://www.lightoj.com/volume_showproblem.php?problem=1005 纸上画一下,找了一下规律,Ank*Cnk. //#pragma comm ...
- 九度OJ 1005:Graduate Admission (排序)
时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:5646 解决:1632 题目描述: It is said that in 2011, there are about 100 graduat ...
- 九度oj 1005
题目1005:Graduate Admission 时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:6182 解决:1791 题目描述: It ...
- 百炼OJ - 1005 - I Think I Need a Houseboat
题目链接:http://bailian.openjudge.cn/practice/1005/ 思路 一个半圆面积每年增长50,已知一个点坐标,求第几年点在半圆内. #include <stdi ...
- Light OJ 1005 - Rooks(DP)
题目大意: 给你一个N和K要求确定有多少种放法,使得没有两个车在一条线上. N*N的矩阵, 有K个棋子. 题目分析: 我是用DP来写的,关于子结构的考虑是这样的. 假设第n*n的矩阵放k个棋子那么,这 ...
- Light Oj 1005
题意: 从 n*n 的棋盘中放置 K 个 行和列不冲突的棋子 思路: 组合数学, 先选 k 个 行, k 个列, 就是 C(n,k) ^ 2; 然后 K 个棋子不相同, K ! 全排列 #includ ...
- Light OJ 1005 - Rooks 数学题解
版权声明:本文作者靖心.靖空间地址:http://blog.csdn.net/kenden23/,未经本作者同意不得转载. https://blog.csdn.net/kenden23/article ...
- [杭电oj][1005]Number Sequence
sky同学在努力地刷题..,在这题卡住了,于是一起研究了一下... 这题本身挺简单的,(1) = 1, f(2) = 1, f(n) = (A * f(n - 1) + B * f(n - 2)) m ...
随机推荐
- 示例 - C#脚本代码采集搜狐NBA球员, 球队和比赛实况
最近 @甜瓜 (QQ:1069629945) 开发了一套NBA数据采集脚本, 我觉得很赞. 经他允许发布出来和大家分享一些经验: 球员球队: http://data.sports.sohu.com/n ...
- 【转】【iOS测试系列】常用测试小插件的使用
背景介绍 由于iOS系统的限制,在非越狱的自动化测试中无法实现一些常用的功能,比如不同应用之间来回切换.模拟全局的点击事件等等.但是在越狱的环境下,这些限制就不存在了,我们可以利用各种小插件来实现我们 ...
- Oracle字符串分割Split(超简单一条sql解决)
) FROM renyuan where name ='张三' 解决如下问题 我现在有一个字段是存:,,3的,而它对应另一张值集表中.eg; 课程人员表 renyuan id name Course ...
- jQuery编程中的一些核心方法简介
调用 jQuery 对象的方法很简单: $('h1').remove(); 大多数 jQuery 方法都是像上面这样被调用的,这些方法都位于 $.fn 命名空间内,这些方法称为 jQuery 对象方法 ...
- 将Oracle数据库转换为SQL Server
(转发)近期为公司的一个项目数据库进行了转换,将Oracle的Db转换为SqlServer(2000或2005均可),一开始在网上找了一些资料,发现有个工具叫SwisSql的,尝试了一下,没成功,继续 ...
- Struts2_day02--Struts2封装获取表单数据方式
Struts2封装获取表单数据方式 原始方式获取表单封装到实体类对象 属性封装(会用) 1 直接把表单提交属性封装到action的属性里面 2 实现步骤 (1)在action成员变量位置定义变量 - ...
- Hibernate_day03--课程安排_表之间关系_一对多操作
Hibernate_day03 上节内容 今天内容 表与表之间关系回顾(重点) Hibernate的一对多操作(重点) 一对多映射配置(重点) 一对多级联操作 一对多级联保存 一对多级联删除 一对多修 ...
- Python学习笔记6-字典Dict
Python内置了字典:dict的支持,dict全称dictionary,在其他语言中也称为map,使用键-值(key-value)存储,具有极快的查找速度. >>> person ...
- js小功能实现
发送随机数手机验证码60秒倒计时 mm.mobileCheck = function(t){ var mobile = $("#user_mobile").val(); if(&q ...
- LAMP集群项目二 初始化系统
1.关闭防火墙 /etc/init.d/iptables stop chkconfig iptables off 2.关闭selinux cat /etc/selinux/config #查看状态 s ...