题目描述
题目分析
由于是求最值,原本考虑贪心,但由于算式过于复杂,首先考虑对算式化简。
进行质因数分解:
因此:
不妨设对于每个,,则上式可化简为:
即
用Vene图也可以求出同样结果。
可是以现在的数据量,求任意两个数的最大公因数都会超时,显然不能直接遍历。故采用记忆化数组预处理数据的方式:设长度为max(Hi)数组cnt[i],表示的是i为多少颗宝石的因数,这样i即为这些宝石的一个公因数。而满足条件cnt[i]>=3的i的最大值,即为所有宝石任取三个的GCD。
for(int i=1;i<=n;i++){
cin>>h[i];
for(int j=1;j<=h[i];j++) {
if(h[i]%j==0){
cnt[j]++;
}
}
}
可这样复杂度仍为。联想到素数判定,如果d是n的约数,那么n/d也是n的约数。所以只需要检查1~√n的所有整数就足够了。这样复杂度就可以降为
我的代码
注意在遍历中一旦求得gcd就使用break退出循环。
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
const int MAX_N = 1e5 + 5;
int cnt[MAX_N];
int H[MAX_N];
int n;
int gcd;
int main() {
//输入
cin >> n;
for (int i = 0; i < MAX_N; i++)
{
cnt[i] = 0;
}
for (int i = 0; i < n; i++)
{
cin >> H[i];
//计数
for (int j = 1; j * j <= H[i]; j++)
{
if (H[i] % j == 0) {
cnt[j]++;
if (j * j != H[i]) {
cnt[H[i] / j]++;
}
}
}
}
//确定最大公约数:
for (int i = MAX_N-1; i >= 0; i--)
{
if (cnt[i] >= 3) {
gcd = i;
break;
}
}
//排序
sort(H, H + n);
int ans = 0;
for (int i = 0; i < n; i++)
{
if (H[i] % gcd == 0) {
if (ans <= 2) {
cout << H[i] << " ";
ans++;
}
else if(ans==2){
cout << H[i];
}
}
}
return 0;
}
思路扩展
为了不使用排序,还可以让cnt数组变成Vector向量容器数组vector<int> cnt[i];。若i为H[i]的因数,将H[i] push_back进Vector中,自然按字典序排列。最后按序输出cnt[gcd].at(0)、cnt[gcd].at(1)、cnt[gcd].at(2)即可。