您的位置:首页 > 其它

【NOIP模拟题】最大公约数

2016-01-28 13:05 351 查看

题意

给定NN个正整数a1,a2,...,ana_1,a_2,...,a_n,在其中选KK个数am1,am2,...,amka_{m_1},a_{m_2},...,a_{m_k},求k×max(gcd(ami))k\times max(gcd(a_{m_i}))。

数据范围:所有输入中的数小于500000500000,k≤nk\leq n。

分析

kk是固定的,只用求max(gcd(ami))max(gcd(a_{m_i}))即可,即选择kk个数,使得这kk个数的最大公约数最大。

首先的想法是正向求解,枚举kk个数,求最大公约数,取最大。

还可以调换顺序,剪枝优化。

好像还是会TLE。

那就考虑参数搜索,转化为判定性问题。

枚举每一个数,求满足这个数是因数的数的个数。

如果个数大于kk,则可以选取这个数。

时间复杂度为O(n1+n2+...+nn)=O(nlogn)O({n\over 1}+{n\over 2}+...+{n\over n})=O(n\log n)。

代码

#include <cstdio>
#include <cctype>

typedef long long Lint;

const int M=500001;

int n,k;
int vis[M];

inline int read(void)
{
int x=0; char c=getchar();
for (;!isdigit(c);c=getchar());
for (;isdigit(c);c=getchar()) x=x*10+c-'0';
return x;
}

int calc(int w)
{
int cnt=0;
for (int j=0;w*j<M;j++) cnt+=vis[w*j];
return cnt;
}

int main(void)
{
n=read(),k=read();
for (int i=1;i<=n;i++) vis[read()]++;

for (int i=M-1;i>=1;i--)
if (calc(i)>=k) {printf("%lld\n",(Lint)i*k);return 0;}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: