题目
有 (n) 个数,最多 (k) 次让所选择的数加一,求 (n) 个数的GCD的最大值
(n,a_ileq 3*10^5,kleq 10^{18})
分析
设答案为 (d) ,也就是使这 (n) 个数尽量靠近 (d) 的倍数。
那也就是使
[kgeq sum_{i=1}^nlceilfrac{a_i}{d}
ceil*d-a_i
]
也就是
[lfloorfrac{k+s}{d}
floorgeq sum_{i=1}^nlceilfrac{a_i}{d}
ceil
]
如果 (large d>max{a_i}) 那么 (large d_{max}=lfloorfrac{k+s}{n} floor),所以如果 (large lfloorfrac{k+s}{n} floor>max{a_i}) 答案为 (large lfloorfrac{k+s}{n} floor)
否则答案一定在 (max{a_i}) 中,枚举答案对于向上取整直接枚举倍数即可,时间复杂度 (O(max{a_i}logmax{a_i}))
代码
#include <cstdio>
#include <cctype>
#include <algorithm>
using namespace std;
typedef long long lll;
lll n,m,s,ans,c[300011],sum,mx,x;
lll iut(){
lll ans=0; char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=ans*10+c-48,c=getchar();
return ans;
}
int main(){
n=iut(),m=iut();
for (int i=1;i<=n;++i)
m+=(x=iut()),mx=mx>x?mx:x,++c[x];
for (int i=mx;i;--i) c[i-1]+=c[i];
if (m/n>mx) return !printf("%lld",m/n);
for (int i=mx;i;--i){
lll sum=0;
for (int j=1;j<=mx;j+=i) sum+=c[j];
if (m/sum>=i) return !printf("%d",i);
}
return 0;
}