#模型转换#[ARC126C] Maximize GCD
题目
有 \(n\) 个数,最多 \(k\) 次让所选择的数加一,求 \(n\) 个数的GCD的最大值
\(n,a_i\leq 3*10^5,k\leq 10^{18}\)
分析
设答案为 \(d\) ,也就是使这 \(n\) 个数尽量靠近 \(d\) 的倍数。
那也就是使
\[k\geq \sum_{i=1}^n\lceil\frac{a_i}{d}\rceil*d-a_i
\]
也就是
\[\lfloor\frac{k+s}{d}\rfloor\geq \sum_{i=1}^n\lceil\frac{a_i}{d}\rceil
\]
如果 \(\large d>\max\{a_i\}\) 那么 \(\large d_{max}=\lfloor\frac{k+s}{n}\rfloor\),所以如果 \(\large \lfloor\frac{k+s}{n}\rfloor>\max\{a_i\}\) 答案为 \(\large \lfloor\frac{k+s}{n}\rfloor\)
否则答案一定在 \(\max\{a_i\}\) 中,枚举答案对于向上取整直接枚举倍数即可,时间复杂度 \(O(\max\{a_i\}\log\max\{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;
}