模拟赛 c7-D wowogcd

题目描述

有 \(N\) 根刻度条,初始长度 \((A_i)\)。

每次操作可任选一根刻度条,长度 + 1;最多执行 \(K\) 次操作。

操作完成后,设所有长度的最大公约数为 \(g\),求能得到的最大 \(g\)。

输入格式

  1. 第一行两个整数 \((N,K)\)
  2. 第二行 \(N\) 个整数 \((A_1,A_2,...,A_N)\)

输出格式

输出最大可行 \(g\)

样例输入 1

3 5
2 5 8

样例输出 1

5

样例解释

调整后全部变为 5,总增量 \((3+0+2=5 \le K),(\gcd(5,5,5)=5)\),无法得到更大公约数。

样例输入 2

4 10
6 10 15 21

样例输出 2

6

样例解释

调整后数字公约数为 \(6\),总增量 \(8 \le 10\)。

数据范围

  • 部分分:\((N\le 2000,\ A_i\le 2000,\ K\le 2000)\)
  • 满分:\((1\le N \le 3\times 10^5,\ 0\le K \le 10^{18},\ 1\le A_i \le 3\times 10^5)\)

算法分析

由于要最大的g,所以可以得到一个式子:射\(f(g)=Σi=1到n,((g-A_i)\ mod\ g)\ mod\ g\ ,\ ans=Max{f(1),f(2),...}\),

将式子变形一下,可以通过前缀和O(1)查询区间和,每一次枚举\(g\),所代表的区间为\([kg+1,(k+1)g]\),目标值为\(l+g-1\),这一段的代价为\(个数\times (l+g-1)-数值的和\),最后只要枚举很少的\(g\)就可以了,完美AC。

AC代码

#include<bits/stdc++.h>
#define ll long long
using namespace std;
int n;
ll k;
int ans = 1;
int mx = 0;
ll sum = 0;
int a[500005];
ll cnt[300005];
ll b[300005];
int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin>>n>>k;
    for(int i = 1; i<=n; i++){
        cin>>a[i];
        mx = max(a[i],mx);
        sum+=a[i];
    }
    ll c = (sum+k)/n;
    if(c>mx){
        cout<<c;
        return 0;
    }
    for(int i = 1; i<=n; i++){
        cnt[a[i]]++;
    }
    for(int i = 1; i<=mx; i++){
        b[i] = b[i-1]+cnt[i]*i;
        cnt[i]+=cnt[i-1];
    }
    for(int i = 2; i<=c; i++){
        ll t = 0;
        for(int j = 1; j<=mx; j+=i){
            int tmp = min(mx,j+i-1);
            ll t1 = cnt[tmp]-cnt[j-1];
            ll t2 = b[tmp]-b[j-1];
            t+=t1*(j+i-1)-t2;
            if(t>k){
                break;
            }
        }
        if(t<=k){
            ans = i;
        }
    }
    cout<<ans;
    return 0;
}

总结

这道题的思路很难想,也不好证明,代码也有一点难度,算数学题,个人认为可以评到青题,算一道比较难的数学证明题。

posted @ 2026-08-17 11:22  xmgene  阅读(10)  评论(0)    收藏  举报