HFUTOJ problem 1343实现总结
2017-04-08 17:48
190 查看
题目
First BloodTime Limit: 1000 MS Memory Limit: 65536 KB
Total Submissions: 799 Accepted: 101
Description
盖伦是个小学一年级的学生,在一次数学课的时候,老师给他们出了一个难题:
老师给了一个正整数 n,需要在不大于n的范围内选择三个正整数(可以是相同的),使它们三个的最小公倍数尽可能的大。盖伦很想第一个解决这个问题,你能帮助盖伦拿到“first blood”吗?
Input
首先是一个正整数T,表示有T组测试数据
每组测试数据是一个正整数n(1<=n<=10^6)
Output
对于每组测试数据,输出最大的最小公倍数,每个输出单独占一行
Sample Input
2
9
7
Sample Output
504
210
Source
安徽省2015年“京胜杯”大学生程序设计竞赛
思路
刚开始想的时候是这样的:- 如果输入n是个奇数,那么结果一定是n*(n-1)*(n-2),因为n与n-1一定互质,n-1与n-2一定互质,那么只要n与n-2互质,这样算出来结果就一定是最大的,而n是奇数,所以n与n-2的公因子gcd必然不含2,之后如果gcd再变大也不可能是n和n-2的公因子,因为n-(n-2)一定大于gcd了。
- 如果n是偶数,那么n与n-2就有公因子2,n与n-2不互质,所以无法取得最大公倍数,那么这里就取n,n-1,n-3就可以了。
- n小于2的时候要单独算结果,因为按上面的想法计算的话会有0结果。
结果是这样的
#include <iostream> using namespace std; int main(void) { int TestTimes = 0; cin >> TestTimes; while (TestTimes--) { int INPUT = 0; cin >> INPUT; if (INPUT == 1) cout << "1" << endl; else if (INPUT == 2) cout << "2" << endl; else if (INPUT == 3) cout << "6" << endl; else if (INPUT % 2) cout << INPUT * (INPUT - 1) * (INPUT - 2) << endl; else cout << INPUT * (INPUT - 1) * (INPUT - 3) << endl; } return 0; }
保(lan)险(de)起(suan)见,我还把n=3的情况也顺便单独拉出来了。
结果错了。。。。。。
因为没有考虑在n为偶数的情况下n与n-3会不会是3的倍数,而换个角度考虑,如果验证的话那么就会陷入n-4、n-5…的死循环中。因此为了解决第三个数究竟应该是多少,我写了个验证互质的函数,然后从n-2开始向下遍历,直到找到与n(n-1)互质的数为止。同时,由于担心这种算法会超时,我在开始遍历之前把num预先变成奇数,然后num-=2遍历,这样时间就可以直接减半。
结果是这样的
#include <iostream> #include <algorithm> using namespace std; bool cheak(int a, int b) { // a > b if (b == 1) return true; /*int num = a % b; if (!num) return false; if (num == 1) return true; cheak(max(b, num), min(b, num));*/ while (b != 0) { int temp = b; b = a%b; a = temp; } if (a == 1) return true; else return false; } int main(void){ int TestTimes = 0; cin >> TestTimes; while (TestTimes--){ int INPUT = 0; cin >> INPUT; if (INPUT == 1) cout << "1" << endl; else if (INPUT == 2) cout << "2" << endl; else { int num = INPUT - 1; if (!(num % 2) && cheak(INPUT*(INPUT - 1), --num)) { cout << INPUT * (INPUT - 1) * num << endl; continue; } while (num -= 2) if (cheak(INPUT*(INPUT-1), num)/* && cheak(INPUT - 1, num)*/) break; cout << INPUT * (INPUT - 1) * num << endl; } } return 0; }
虽然做了时间优化,但是还是超时了(这时间尼玛扣得真死 = =)。
没办法,只能去网上找了解答。在看过一个超级高级的算法后我不禁陷入了懵逼,因为完全看不懂
长这样的:
算法描述
任意正整数v与v-1必定互质,v*(v-1)为两个数最小公倍数的最大值,v由最大范围n选起;
再选一数u,由于两数的最小公倍数与最大公约数之积等于两数之积,因此最小公倍数表示为(v*(v-1)u)/gcd(v(v-1),u),故在V选定的情况下最小公倍数的大小由u/gcd(v*(v-1),u)决定,因此u不能与v或v-1相同,u由v-2开始选取,直到v(v-1)*u < max_lcm为止(因为最小公倍数的最大值为三个数的乘积),记录这期间的最大的最小公倍数值max_lcm;
v值减一,若max_lcm < v*(v-1)(v-2),则u由v-2开始再进行一次第2步,完成后max_lcm 与 v(v-1)*(v-2)比较,直到不满足“<”,输出max_lcm。
注意事项
注意特殊值
n=1时,v-1,v-2不存在,max_lcm=1;
n=2时,v-2不存在,max_lcm=2;
shenmegui!!!(╯‵□′)╯︵┻━┻
完全看不懂啊!!!(╯‵□′)╯︵┻━┻
既然看不懂自然也没法实现了。。。起码我没法用这个算法自己写个程序出来,哪怕是用背的都不行。。。。
好几天之后,我终于在网上找到了个神奇的算法:
思路:
记住n是奇数结果就是 n*(n-1)*(n-2);
n时偶数且不是3的倍数 n*(n-1)(n-3); 是3的倍数 (n-1)(n-2)*(n-3)
用long long保存
???
嗯,我也不能理解,原因在于这算法乍看起来和我的没啥区别,但是能过。。。。区别在于,在我上面碰到无限验证的循环之后。。。他没有用n*(n-1)?这样的算法了,而是用了(n-1)(n-2)*(n-3)。。。
??????
我不能理解啊,问了别人这是为啥,结果得到的答案是“这是数学常识,记住就好了”。
?
b64a
???????
这数学常识颠覆了我20年的世界观啊。。。。。从来没听说过这玩意啊。。。。
虽然我最后还是靠这个算法过了,但是我至今仍未能理解。。。
我可能需要个高数老师来帮帮我。。。
结果
#include<iostream> using namespace std; int main() { int TestTime = 0; long long num = 0; cin >> TestTime; while(TestTime--){ cin >> num; if (num <= 2) cout << num << endl; else if (num%2) cout << num*(num-1)*(num-2) << endl; else if (num%3) cout << num*(num-1)*(num-3) << endl; else cout << (num-1)*(num-2)*(num-3) << endl; } return 0; }
p.s 不知道为啥,只要我把num的定义放在循环体里面,就会有结果错误,又是个我不能理解的迷。。。。。
相关文章推荐
- HFUTOJ problem 1357实现总结
- HFUTOJ problem 1299实现总结
- HFUTOJ problem 1356实现总结
- OJ第四批——Problem B: 类重载实现矩阵加法
- QUST'S OJ problem 1355 函数实现二维数组的行列转换
- HFUTOJ problem 1354实现总结
- python3 实现 A+B Problem(百练OJ:1000)
- SDUST-OJ-1681 Problem 求集合的交并补集(不用STL,手写单链表实现)
- Android 并行自动化测试系统 实现总结
- LINQ to Entities 实现sql 关键字"In"方式总结
- <<UNIX环境高级编程>>学习总结——第二章:UNIX标准化及实现
- 杭电OJ 第一周 Problem J:吃糖果
- 排序算法总结(c++实现)
- Android实现屏幕旋转方法总结
- 忘记密码 重置密码实现总结
- 告别ADO.NET实现应用系统无缝切换的烦恼(总结篇)
- Vue底层实现原理总结
- Cobar-Client 实现策略总结
- 哈理工oj 1739 sort problem【思维、水题】
- 总结一下,在MVC下利用JQUERY实现AJAX提交,并实现AJAX .NET的UpdateProgress功能