您的位置:首页 > 其它

北大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。循环不多,时间挺快就搞定了。

但是,这里有个问题,也可能是大多数同学报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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息