最大公约数

https://zybuluo.com/ysner/note/1175822

题面

现有(n)个数,询问选出(k)个数的(gcd)的最大值。

  • (30pts) (nleq20)
  • (60pts) 保证输入中所有数小于(5000)
  • (100pts) 保证输入中所有数小于(500000)
  • (kleq n)

解析

(nleq20)

(O(2^n))枚举。

(nleq5000)

枚举(gcd)最大值,看是否有(k)个数能将其除尽。

(nleq5*10^5)

话说我想了半天为什么不给出(n)的范围,竟然没想到是因要开桶,(n)的范围无意义。。。
于是我们开个桶(a[i])记录每个数出现多少次。
然后枚举(gcd)最大值。
要判断有多少个数能将其除尽,直接枚举(t)(sum a[gcd*t](tin N^*))即可。
复杂度最坏为$$O(n+frac{n}{2}+frac{n}{3}+...+1)$$
等价于(O(nlogn))

#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#define ll long long
#define re register
#define il inline
#define fp(i,a,b) for(re int i=a;i<=b;i++)
#define fq(i,a,b) for(re int i=a;i>=b;i--)
using namespace std;
const int N=5e5+100;
int n,k,a[N],ans=1,mx;
int main()
{
  freopen("gcd.in","r",stdin);
  freopen("gcd.out","w",stdout);
  n=gi();k=gi();
  fp(i,1,n)
    {
      re int x=gi();mx=max(mx,x);
      a[x]++;
    }
  fq(i,mx,1)
    {
      re int sum=0;
      for(re int j=1;j*i<=mx;j++) sum+=a[j*i];
      if(sum>=k) {printf("%lld
",1ll*k*i);return 0;}
    }
  fclose(stdin);
  fclose(stdout);
  return 0;
}
原文地址:https://www.cnblogs.com/yanshannan/p/9155453.html