北大ACM1006报WrongAnswer解决思路
2017-05-26 08:49
79 查看
在1002题之后,后面的1003到1005实在太过简单,所以就不单独发博文阐述了,有问题可以在评论下面回复。
我们详细讨论一下1006题,题目的大致意思大概是找一个公倍数的问题,也就是这三个数在什么时候有一个可以被整除的时间。除了p,e,i这三个参数,为了迷惑你题目还特地弄了一个起始时间,也就是d,事实上这个并没有什么卵用,唯一的作用只是让你在最后减去d,仅此而已。因此题目的关键就是找到这个日期。而且题目中给了一个很明显的暗示,题中说,所求的时间都会小于21252,有点数学基础的同学会发现这其实就是23 28 33这三个数的最小公倍数,也就是说最后求得的日期一定以21252为周期进行改变。
在明白了这个问题之后呢,我们还需要一点基础数论的知识,关于同余。事实上,我们在得到日期后,第一件事大家都会明白就是把各自对应的数在23 28 33求余,求出的余数实质上对应着三个正整数,i,j,k。例如对于给定的一组数据 283 102 23 320。你先求余,得到 7 18 23 320。然后按照数论的同余写成这个样子。
23+33*k = 7 (mod 23) = 18 (mod 28) (这里是全等号)
也就是我们寻找一个正整数k 满足上面的式子,而且;由于时间小于21252,所以k一定小于645。循环不多,时间挺快就搞定了。
当然更快的办法你可以使用中国剩余数定理。最快的办法自然是查表。事实上你只有 23*28*33种情况。用MATLAB导出来搞成一张查找表。是解决这个问题最快的办法。
代码如下:
//这道题稍微用了些数论的知识进行计算,就是公共余数的问题,但是这道题的关键点在于对于answer[m]进行限幅,特别是当输入33 33 33 33时,
//会出现0的错误选项,之前提交的错误就出现在这里。
#include<iostream>
using namespace std;
int main()
{
int a, b, c, f = 0;
int n = 0;
int p[1000],e[1000],i[1000],d[1000];
int answer[1000];
int m = 0;
for (m = 0; m < 1000; m++)
{
cin >> a >> b >> c >> f;
if (a < 0 && b < 0 && c < 0 && f < 0)
{
n = m + 1;
break;
}
p[m] = a % 23;
e[m] = b % 28;
i[m] = c % 33;
d[m] = f;
}
for (m = 0; m < n-1; m++)
{
int k = 0;
for (k = 1; k < 645; k++)
{
if ((33 * k + i[m]-p[m]) % 23 == 0 && (33 * k + i[m]-e[m]) % 28 == 0)
{
answer[m] = (k * 33 + i[m]) - d[m];
if (answer[m] >21252)
{
answer[m] = answer[m] - 21252;
}
if (answer[m] < 1)
{
answer[m] = answer[m] + 21252;
}
break;
}
}
cout << "Case " << m + 1 << ": the next triple peak occurs in " << answer[m] << " days." << endl;
}
system("pause");
return 0;
}
我们详细讨论一下1006题,题目的大致意思大概是找一个公倍数的问题,也就是这三个数在什么时候有一个可以被整除的时间。除了p,e,i这三个参数,为了迷惑你题目还特地弄了一个起始时间,也就是d,事实上这个并没有什么卵用,唯一的作用只是让你在最后减去d,仅此而已。因此题目的关键就是找到这个日期。而且题目中给了一个很明显的暗示,题中说,所求的时间都会小于21252,有点数学基础的同学会发现这其实就是23 28 33这三个数的最小公倍数,也就是说最后求得的日期一定以21252为周期进行改变。
在明白了这个问题之后呢,我们还需要一点基础数论的知识,关于同余。事实上,我们在得到日期后,第一件事大家都会明白就是把各自对应的数在23 28 33求余,求出的余数实质上对应着三个正整数,i,j,k。例如对于给定的一组数据 283 102 23 320。你先求余,得到 7 18 23 320。然后按照数论的同余写成这个样子。
23+33*k = 7 (mod 23) = 18 (mod 28) (这里是全等号)
也就是我们寻找一个正整数k 满足上面的式子,而且;由于时间小于21252,所以k一定小于645。循环不多,时间挺快就搞定了。
但是,这里有个问题,也可能是大多数同学报Wrong Answer的问题
那就是你所求的结果必须严格在 1 (包括1)到 21252(包括21252)之间,当你的结果为0时,是会报错的,必须给出21252。所以做个限幅就可以。当然更快的办法你可以使用中国剩余数定理。最快的办法自然是查表。事实上你只有 23*28*33种情况。用MATLAB导出来搞成一张查找表。是解决这个问题最快的办法。
代码如下:
//这道题稍微用了些数论的知识进行计算,就是公共余数的问题,但是这道题的关键点在于对于answer[m]进行限幅,特别是当输入33 33 33 33时,
//会出现0的错误选项,之前提交的错误就出现在这里。
#include<iostream>
using namespace std;
int main()
{
int a, b, c, f = 0;
int n = 0;
int p[1000],e[1000],i[1000],d[1000];
int answer[1000];
int m = 0;
for (m = 0; m < 1000; m++)
{
cin >> a >> b >> c >> f;
if (a < 0 && b < 0 && c < 0 && f < 0)
{
n = m + 1;
break;
}
p[m] = a % 23;
e[m] = b % 28;
i[m] = c % 33;
d[m] = f;
}
for (m = 0; m < n-1; m++)
{
int k = 0;
for (k = 1; k < 645; k++)
{
if ((33 * k + i[m]-p[m]) % 23 == 0 && (33 * k + i[m]-e[m]) % 28 == 0)
{
answer[m] = (k * 33 + i[m]) - d[m];
if (answer[m] >21252)
{
answer[m] = answer[m] - 21252;
}
if (answer[m] < 1)
{
answer[m] = answer[m] + 21252;
}
break;
}
}
cout << "Case " << m + 1 << ": the next triple peak occurs in " << answer[m] << " days." << endl;
}
system("pause");
return 0;
}
相关文章推荐
- 显示器黑屏故障解决思路
- 关于FSO静态生成技术的应用范围之解决思路
- 正确而优美的解决logout问题的思路
- 项目统一开发管理解决方案思路[项目组成员同时做很多项目的解决思路探讨]
- 项目统一开发管理解决方案思路[项目组成员同时做很多项目的解决思路探讨]
- Log actively being archived by another process的问题解决思路
- 调整思路:用交换机解决局域网安全
- 解决xml中&符号"&amp;"输入问题的一个思路
- 换一种思路:解决Ajax程序与IE7不兼容的问题
- 制作web安装文件时遇到的几个小问题及其解决思路
- 制作Web安装文件时遇到的几个小问题及其解决思路
- ASP按定制格式导出word文件的完美解决思路
- ajax页面刷新问题的解决思路
- 用户上传产生无效文件的解决思路
- 制作web安装文件时遇到的几个小问题及其解决思路(续一)
- 解决i18n的问题有三种经典思路
- 解决网页浏览故障的一般思路
- Exchange出站队列堵塞解决思路 推荐
- 关于刷新重复提交的一种解决思路
- 针对vb中scriptcontrol 数组调用另类解决思路