AT_arc126_c [ARC126C] Maximize GCD 题解
特判掉最终 $\gcd>\max\limits_{i=1}^na_i$ 的情况,这部分是平凡的。
倒序枚举最终 $\gcd$ 为 $g\in[1,\max\limits_{i=1}^na_i]$,考虑怎么判断 $\gcd$ 能否取得 $g$。
发现若 $\forall i,g|a_i$ 则 $g=\gcd\limits_{i=1}^na_i$。(反证法:一定有 $g|\gcd\limits_{i=1}^na_i$,而若 $\gcd\limits_{i=1}^n>g$ 则枚举 $g'=\gcd\limits_{i=1}^n$ 时程序已经结束。)
$\forall p,gp\le\max\limits_{i=1}^na_i$ 统计将 $(gp,g(p+1)]$ 间的数都改为 $g(p+1)$ 的代价,开桶容易做到单次 $O(1)$。
若总代价 $\le k$,则 $\gcd$ 可以取得 $g$。复杂度 $O(\sum\limits_{i=1}^W\dfrac Wi)=O(W\log W)$。
#include <cstdio>
#include <algorithm>
#define int long long
using namespace std;
int n, m, k, s, a[300050], c[300050];
signed main()
{
scanf("%lld%lld", &n, &k);
for (int i = 1; i <= n; ++i)
scanf("%lld", a + i), ++c[a[i]], s += a[i], m = max(m, a[i]);
for (int i = 1; i <= 300000ll; ++i)
c[i] += c[i - 1];
if (k >= n * m - s)
{
k -= n * m - s;
printf("%lld", m + k / n);
return 0;
}
for (int i = m, z; i; --i)
{
z = 0;
for (int j = i; j - i <= 300000ll; j += i)
z += j * (c[min(j, 300000ll)] - c[j - i]);
if (z - s <= k)
{
printf("%lld", i);
return 0;
}
}
return 0;
}

浙公网安备 33010602011771号