arc126c

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 nk ,就可以贪心的将所有数加一,同时 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)3105 在无论何种分配下都成立

那么,我们可以尝试枚举 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)xprekxcntkxx

那么对于数 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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值