arc126c
思路
首先,有不等式 gcd ( a 1 , a 2 , . . . , a n ) ≤ min ( a 1 , a 2 , . . . , a n ) \gcd(a_1,a_2,...,a_n) \leq \min(a_1,a_2,...,a_n) gcd(a1,a2,...,an)≤min(a1,a2,...,an)
如果 k 足够大,以至于所有的数都加到 max ( a 1 , a 2 , . . . , a n ) \max(a_1,a_2,...,a_n) max(a1,a2,...,an) 后还有剩余,那么此时,每当 n ≤ k n\leq k n≤k ,就可以贪心的将所有数加一,同时 gcd 加一
如果 k 不够大,我们可以断定 gcd ( a 1 , . . . , a n ) < max ( a 1 , a 2 , . . . , a n ) ≤ 3 ∗ 1 0 5 \gcd(a_1,...,a_n) < \max(a_1,a_2,...,a_n) \leq 3*10^5 gcd(a1,...,an)<max(a1,a2,...,an)≤3∗105 在无论何种分配下都成立
那么,我们可以尝试枚举 gcd 的值,设为 x x x
不难发现 k x + 1 kx+1 kx+1 到 ( k + 1 ) x (k+1)x (k+1)x 之内的数的最优解是变成 ( k + 1 ) x (k+1)x (k+1)x
设 c n t i cnt_i cnti 为值不比 i i i 大的数的个数, p r e i pre_i prei 为所有小于等于 i i i 的数距离值 i i i 的距离的总和
不难发现 c n t i + 1 = c n t i + n u m i + 1 cnt_{i+1} = cnt_i+num_{i+1} cnti+1=cnti+numi+1 且 p r e i + 1 = p r e i + c n t i pre_{i+1}=pre_{i}+cnt_i prei+1=prei+cnti ,其中 n u m i num_i numi 代表值等于 i i i 的数的个数
那么从 k x + 1 kx+1 kx+1 到 ( k + 1 ) x (k+1)x (k+1)x 的代价就是 p r e ( k + 1 ) x − p r e k x − c n t k x ∗ x pre_{(k+1)x}-pre_{kx}-cnt_{kx}*x pre(k+1)x−prekx−cntkx∗x
那么对于数 x x x ,统计一次的复杂度为 Θ ( 3 e 10 / x ) \Theta(3e10/x) Θ(3e10/x)
总复杂度为 Θ ( N + 3 e 10 log 3 e 10 ) \Theta(N+3e10\log{3e10}) Θ(N+3e10log3e10)
代码
#include <bits/stdc++.h>
using namespace std;
#ifdef _DEBUG
#define pr1(x) cout << x << ' ';
#define pr2(x) cout << x << endl;
#else
#define pr1(x)
#define pr2(x)
#endif
typedef long long ll;
typedef unsigned long long ull;
typedef const int& cint;
typedef pair<int, int> pii;
const int mod = 1e9+7;
const int inf_int = 0x7fffffff;
const ll inf_ll = 0x7fffffffffffffff;
const double ept = 1e-9;
ll n, k;
ll a[600300];
ll cnt[600300];
ll pre[600300];
int main() {
ll mx = 0;
ll sum = 0;
cin >> n >> k;
for(int i=1; i<=n; i++) {
cin >> a[i];
++cnt[a[i]];
mx = max(mx, a[i]);
sum += a[i];
}
for(int i=1; i<=2*mx; i++) {
cnt[i] += cnt[i-1];
pre[i] += pre[i-1] + cnt[i-1];
}
// for(int i=1; i<=mx; i++)
// cout << pre[i] << ' ';
// cout << endl;
if(1ll*mx*n-k <= sum) {
k -= 1ll*mx*n-sum;
cout << mx + k/n << endl;
}
else {
int ans = 1;
for(int i=2; i<mx; i++) {
ll rsum = 0;
for(int j=i; j<2*mx; j+=i) {
int l = j-i;
rsum += pre[j] - pre[l] - 1ll*cnt[l]*i;
}
// cout << i << ' ' << rsum << endl;
if(rsum <= k) ans = i;
}
cout << ans << endl;
}
return 0;
}