POJ1044 Date bugs
题目来源:http://poj.org/problem?id=1044
题目大意:
与众所周知的”千年虫“类似,某些计算机上存在日期记录的bug。它们的时钟有一个年份周期,每当到达最大值时,就会自动跳回到最小值。现给定一组这样的时钟,给出它们显示的年份y[i],周期的起始年份a[i],周期的结束年份b[i],求可能的真实年份的最小值。真实年份应该比所有的a[i]都大。
输入:多个测试用例组成,第一行为时钟数n,接下来的n行每行为一个时钟的信息,含三个整数y[i],a[i],b[i].含义见上面的描述。n为0时表示输入结束。
输出:输出计算得的真实年份,若找不到小于10000的真实年份,输出信息:"Unkown bugs detected.",用空格隔开每个用例的输出。格式见sample。
Sample Input
2
1941 1900 2000
2005 1904 2040
2
1998 1900 2000
1999 1900 2000
0
Sample Output
Case #1:
The actual year is 2141. Case #2:
Unknown bugs detected.
这题与前面的一些题目相比简单太多了。记b[i]-a[i]为t[i]表示每个时钟的周期,那么真实年份可以设为y[i] + k[i] * t[i];一开始我打算先求所有周期的最小公倍数限制试探k的范围,后来发现限制了真实年份最大值才10000,很可能比最小公倍数小很多,而且公倍数还很有可能发生溢出等情况,所以还不如直接以它作为限制界限。以y[0] + k * t[0]为真实年份的试探值,假设为Y,那么对于其他的时钟都应该满足Y=y[i] + k[i] * t[i],其中k[i]为非负整数。所以只要Y - y[i] >= 0 且 Y - y[i] 可以被t[i]整除,那么这个真实年份的试探值对于第i个时钟就是可行的。所以,从0开始试探每个k,直到找到对所有时钟都可行的Y或者Y超过10000时停止即可。
//////////////////////////////////////////////////////////////////////////
// POJ1044 Date bugs
// Memory: 264K Time: 0MS
// Language: C++ Result: Accepted
////////////////////////////////////////////////////////////////////////// #include <iostream> using namespace std; int n;
int y[];
int a[];
int t[]; int main (void) {
int case_id = ;
while (true) {
cin >> n;
if (n == ) break;
for (int i = ; i < n; ++i) {
cin >> y[i] >> a[i] >> t[i];
t[i] -= a[i]; //计算出周期即可,b[i]以后不会再用到
}
int k = ;
//依次检验每个k是否可行
while ((a[] = y[] + k * t[]) < ) {
bool flag = true;
for (int i = ; i < n; ++i) {
int p = a[] - y[i];
if (p < || p % t[i] != ) {
flag = false;
break;
}
}
if (flag) {
cout << "Case #" << ++case_id <<":" << endl;
cout << "The actual year is " << a[] << "." << endl << endl;
break;
}
++k;
}
if (a[] >= ) {
cout << "Case #" << ++case_id <<":" << endl;
cout << "Unknown bugs detected." << endl << endl;
}
}
system("pause");
return ;
}
由于一开始想要计算所有周期的最小公倍数,所以顺便回顾了一下求最小公倍数的方法(以两个数为例),在下面也记录一下吧。
小学知识告诉我们(==!):两个数的积除以两个数的最大公约数(gcd)等于它们的最小公倍数(lcm)。
所以只要求出了gcd就很容易得到lcm了。
求gcd的经典算法是欧几里德算法,或称辗转相除法。该算法依赖与下面的性质:
记两个整数a,b的最大公约数为gcd(a, b), 那么有定理:gcd(a, b) = gcd(b, a%b)
定理证明:设 a = k * b + r, 则 r = a % b;
假设d是a和b的一个公约数, 那么d|a(表示d可以整除a),且d|b, 而 r = a - k * b,所以显然有d|r,故d也是a % b的约数,即 d 是 b 和 a % b 的公约数。
假设d是b和a % b的一个公约数,那么d|b, 且d|r,而 a = k * b + r, 所以有d|a, 故d也是a的约数,即d是 a 和 b 的公约数。
由以上两条知 a、b 两数的公约数与 b、 a % b两数的公约数完全一致,所以它们的最大公约数也一定相等。
所以有:gcd(a, b) = gcd(b, a%b)
辗转相除法用C++描述非常简洁:
int Gcd(int a, int b) {
if(b == )
return a;
return Gcd(b, a % b);
}
去掉递归写为迭代形式:
int Gcd(int a, int b) {
while(b != ) {
int r = b;
b = a % b;
a = r;
}
return a;
}
除了传统的欧几里德算法,还有另一种求最大公约数的算法叫Stein算法。
Stein算法主要是为了解决欧几里德算法在遇到大素数需要求模时产生的问题:
”考虑现在的硬件平台,一般整数最多也就是64位,对于这样的整数,计算两个数之间的模是很简单的。对于字长为32位的平台,计算两个不超过32位的整数的模,只需要一个指令周期,而计算64位以下的整数模,也不过几个周期而已。但是对于更大的素数,这样的计算过程就不得不由用户来设计,为了计算两个超过64位的整数的模,用户也许不得不采用类似于多位数除法手算过程中的试商法,这个过程不但复杂,而且消耗了很多CPU时间。对于现代密码算法,要求计算128位以上的素数的情况比比皆是,设计这样的程序迫切希望能够抛弃除法和取模。"
所以Stein算法中只有整数的移位和加减法,便于计算机的处理。
Stein算法基于下面的结论:
gcd(a,a) = a;
gcd(ka, kb) = k gcd(a,b);
当k与b互为质数,则gcd(ka,b)=gcd(a,b)。
算法的C++实现:
int Gcd(int a, int b) {
if(a == ) return b;
if(b == ) return a;
if(a % == && b % == ) return * gcd(a >> , b >> );
else if(a % == ) return gcd(a >> , b);
else if(b % == ) return gcd(a, b >> );
else return gcd(abs(a - b) / 2, min(a, b));
}
对于代码的最后一行解释如下:
这种情况下a和b都为奇数,假设a>b, 设a = b + s .那么,有gcd(a, b) = gcd(s / 2, b).
因为上面证明过gcd(a,b) = gcd(b, a%b), 这里同样令a = k * b + r, (k >= 1),则 s=(k - 1) * b + r.
gcd(b, s) = gcd(b, (k - 1) * b + r) = gcd(b, r); 又a、b都是奇数, 那么s一定的偶数,所以gcd(b, s) = gcd(b, s/2).
最终得到a、b都为奇数时,gcd(a, b) = gcd(abs(a - b) / 2, min(a, b)).
POJ1044 Date bugs的更多相关文章
- OpenJudge / Poj 1044 Date bugs C++
链接地址: Poj:http://poj.org/problem?id=1044 OpenJudge:http://bailian.openjudge.cn/practice/1044/ 题目: 总时 ...
- POJ 1044: Date bugs
题目描述 There are rumors that there are a lot of computers having a problem with the year 2000. As they ...
- 第一次写博客Poj1044
Date bugs Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 3005 Accepted: 889 Descript ...
- linux命令总结之date命令
命令简介: date 根据给定格式显示日期或设置系统日期时间.print or set the system date and time 指令所在路径:/bin/date 命令语法: date [OP ...
- POJ题目排序的Java程序
POJ 排序的思想就是根据选取范围的题目的totalSubmittedNumber和totalAcceptedNumber计算一个avgAcceptRate. 每一道题都有一个value,value ...
- Linux学习之十-Linux系统时间
Linux系统时间 1.date命令用于查看以及修改Linux系统的时间,关于date命令的详细帮助文档如下 [root@localhost ~]# date --help Usage: date [ ...
- Linux命令学习总结:date命令
命令简介: date 根据给定格式显示日期或设置系统日期时间.print or set the system date and time 指令所在路径:/bin/date 命令语法: date [OP ...
- man/ls/clock/date/echo笔记
login: 用户名:用户ID 认证机制:Authentication授权:Authorization审计:Audition (日志) prompt,命令提示符:命令:magic numb ...
- Linux命令学习总结:date命令【转】
本文转自:http://www.cnblogs.com/kerrycode/p/3427617.html 命令简介: date 根据给定格式显示日期或设置系统日期时间.print or set the ...
随机推荐
- Android Studio & Butter Knife —— 快速开发
Butter Knife是一个Android的注解框架,可以帮助用户快速完成视图.资源与对象的绑定,完成事件的监听.(也就是少写findViewById()) 具体的介绍可以参考官方主页: http: ...
- bzoj3595 方伯伯的oj
有$n$个数,一开始是$1~n$,有$m$次操作 1.把编号为$x$的人编号改为$y$,保证$y$没出现过 2.把编号为$x$的人提到第一名 3.把编号为$x$的人怼到最后一名 4.查询排名为$x$的 ...
- @@cursor_rows变量解析
刚刚看了@@curosr_rows这个全局变量,发现这个变量挺有意思.要懂得这个变量的意义,基本上牵扯到cursor一些比较容易忽视的内容. @@cursor_rows是用来记录当前游标的数量,也就从 ...
- ACM学习历程—POJ 3764 The xor-longest Path(xor && 字典树 && 贪心)
题目链接:http://poj.org/problem?id=3764 题目大意是在树上求一条路径,使得xor和最大. 由于是在树上,所以两个结点之间应有唯一路径. 而xor(u, v) = xor( ...
- [转]PNG8和PNG24的区别
首先我们要知道: 1.png8和png24的根本区别,不是颜色位的区别,而是存储方式不同. 2.png8有1位的布尔透明通道(要么完全透明,要么完全不透明),png24则有8位(256阶)的布尔透明通 ...
- netty支持的协议
流经网络的数据总是具有相同的类型:字节.这些字节是如何流动的主要取决于我们所说的 网络传输--一个帮助我们抽象底层数据传输机制的概念.用户并不关心这些细节:他们只想确保他们的字节被可靠地发送和接收. ...
- 报错apachectl -t
httpd: apr_sockaddr_info_get() failed for wwwhttpd: Could not reliably determine the server's fully ...
- sharepoint Foundation 2013 error
安装必须软件时提示以下错误 错误提示日志: 015-05-28 10:40:25 - Request for install time of 应用程序服务器角色.Web 服务器(IIS)角色2015- ...
- CSS之BFC详解
What:了解该知识点的概念,本质以及有关牵扯到的相关知识概念 BFC这个东西说常见的话你可能不觉得,但是你肯定会常用,也许你在用的时候也没想到BFC这东西.网上也有很多写这些东西的文章,但是自己写一 ...
- SpringCloud01 服务提供者和消费者
说明:服务消费者直接利用RestTemplate调用服务提供者,这种使用方式只是适用于微服务数量比较少的项目,如果微服务的数量比较多建议使用SpringCloud提供的Eureaka组件. 注意:实现 ...