1 条题解

  • 0
    @ 2026-4-5 21:30:08

    D. Split Plus K 题解

    问题描述

    黑板上有 nn 个正整数 a1,a2,,ana_1, a_2, \dots, a_n,给定正整数 kk。每次操作:选择一个数 xx,擦掉它,写上两个正整数 y,zy, z 满足 y+z=x+ky+z = x + k。问能否通过若干次操作使得所有数相等,并求出最少操作次数。


    关键变换

    x=xkx' = x - k,将原问题中的每个数都减去 kk
    原操作 y+z=x+ky+z = x+k 变为:

    $$(y'+k)+(z'+k) = (x'+k)+k \;\Longrightarrow\; y' + z' = x'. $$

    于是变换后的问题等价于:
    初始有 nn 个数 ai=aika_i' = a_i - k,每次操作选择一个数 xx',擦掉它,写上两个数 y,zy', z' 满足 y+z=xy'+z' = x'
    目标:使所有数相等(记为 mm'),且原数 m=m+km = m'+k 必须为正整数。
    操作次数 = 最终数的个数 - 初始个数 nn


    数学模型

    设最终所有数变为 mm(原问题),对应 m=mkm' = m - k
    对初始的 aia_i,设它经过 pip_i 次操作后变成 pi+1p_i+1mm。每次操作总和增加 kk,因此:

    ai+pik=(pi+1)m.a_i + p_i k = (p_i+1) m.

    d=mkd = m - k,则 m=d+km = d + k,代入得:

    $$a_i - k = (p_i+1) d \;\Longrightarrow\; a_i' = q_i d, $$

    其中 qi=pi+1q_i = p_i+1 为正整数。
    最终数的总个数为 qi=aid\sum q_i = \sum \frac{a_i'}{d},初始有 nn 个数,所以操作次数为:

    ans=i=1naidn.\text{ans} = \sum_{i=1}^n \frac{a_i'}{d} - n.

    这里 dd 必须整除每一个 aia_i',且 d0d \neq 0(若 d=0d=0 则所有 ai=0a_i'=0,单独处理)。
    同时 m=d+k>0m = d+k > 0 必须成立,即 d>kd > -k。由于 k1k \ge 1,当 dd 为负数且绝对值很大时可能破坏正性,但下面将证明只需考虑 ddaia_i' 同号的情况。


    可行性分析

    • 若所有 ai=0a_i' = 0,即所有 ai=ka_i = k,则已经全等,答案为 00
    • 否则,dd 必须非零。由于 ai=qida_i' = q_i d,所有 aia_i' 必须同号(全正或全负),否则不可能同时被同一个非零 dd 整除且 qiq_i 为正整数。
    • 若存在某个 ai=0a_i' = 0 而其他非零,则 0=qid0 = q_i d 要求 d=0d=0qi=0q_i=0,前者矛盾,后者不可能(qi1q_i\ge1),因此无解。

    所以可行当且仅当

    • 所有 aia_i' 全为正,或全为负,且没有零。

    最小化操作次数

    当所有 aia_i' 同号时,取 dd 为它们的最大公因数(带符号)能使 ai/d\sum a_i'/d 最小(因为 dd 越大,每个商越小)。
    g=gcd(a1,a2,,an)g = \gcd(|a_1'|, |a_2'|, \dots, |a_n'|),则:

    • 若所有 ai>0a_i' > 0,取 d=gd = g
    • 若所有 ai<0a_i' < 0,取 d=gd = -g(此时 ai/d=ai/ga_i'/d = |a_i'|/g 为正整数)。

    此时操作次数为:

    ans=i=1naign.\text{ans} = \sum_{i=1}^n \frac{|a_i'|}{g} - n.

    注意当所有 aia_i 已经相等(且不等于 kk)时,aia_i' 全相等非零,g=aig = |a_i'|,代入得 ans=nn=0\text{ans}=n - n = 0,符合预期。


    正确性补充说明

    • ai>0a_i' > 0 时,d=g>0d = g > 0,则最终数 m=d+k>k1m = d + k > k \ge 1,且每次分裂得到的 y,zy,z 在原问题中为 y+k,z+ky'+k, z'+k,因为 y,z>0y',z' > 0,所以 y,z>k1y,z > k \ge 1,均为正整数,符合要求。
    • ai<0a_i' < 0 时,d=g<0d = -g < 0,则 m=d+k=kgm = d + k = k - g。由于 ai=aik<0a_i' = a_i - k < 0,故 ai<ka_i < k,而 gg 整除 ai|a_i'|,可能使 mm 很小甚至非正?实际上,由 ai=qida_i' = q_i dd<0d<0qi>0q_i>0,得 aid<0a_i' \le d < 0,故 aid=g|a_i'| \ge |d| = g,所以 $m = k - g \ge k - |a_i'| \ge k - (k - a_i) = a_i > 0$,因此 mm 仍为正整数。同时分裂出的 y,zy,z 在原问题中为 y+k,z+ky'+k, z'+k,由于 y,z>0y',z' > 0,故 y,z>ky,z > k,而 ai<ka_i < k,所以新写的数比原来的大,但仍是正整数,符合操作要求。

    算法步骤

    1. 读入 n,kn, k 和数组 aa
    2. 计算 bi=aikb_i = a_i - k
    3. 若所有 bi=0b_i = 0,输出 00
    4. 若存在 bi=0b_i = 0bib_i 有正有负,输出 1-1
    5. 否则,计算 g=gcd(b1,b2,,bn)g = \gcd(|b_1|, |b_2|, \dots, |b_n|)
    6. 输出 (i=1nbig)n\left(\sum_{i=1}^n \frac{|b_i|}{g}\right) - n

    复杂度 O(n+logmaxai)O(n + \log \max a_i),满足题目限制。


    代码实现(C++)

    #include <bits/stdc++.h>
    using namespace std;
    using ll = long long;
    
    ll gcd(ll a, ll b) {
        while (b) { ll t = b; b = a % b; a = t; }
        return a;
    }
    
    void solve() {
        int n;
        ll k;
        cin >> n >> k;
        vector<ll> a(n);
        for (int i = 0; i < n; ++i) cin >> a[i];
    
        vector<ll> b(n);
        for (int i = 0; i < n; ++i) b[i] = a[i] - k;
    
        // 检查是否全零
        bool all_zero = true;
        for (ll x : b) if (x != 0) { all_zero = false; break; }
        if (all_zero) {
            cout << "0\n";
            return;
        }
    
        // 检查是否有零或异号
        bool has_zero = false;
        bool pos = false, neg = false;
        for (ll x : b) {
            if (x == 0) has_zero = true;
            else if (x > 0) pos = true;
            else neg = true;
        }
        if (has_zero || (pos && neg)) {
            cout << "-1\n";
            return;
        }
    
        // 计算 gcd 绝对值
        ll g = 0;
        for (ll x : b) {
            g = gcd(g, abs(x));
        }
    
        ll total = 0;
        for (ll x : b) {
            total += abs(x) / g;
        }
        cout << total - n << "\n";
    }
    
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        int t;
        cin >> t;
        while (t--) solve();
        return 0;
    }
    

    样例验证

    输入:

    9
    2 1
    3 4
    2 3
    7 11
    3 10
    100 40 100
    2 1
    1 2
    2 2
    1 2
    1 327869541
    327869541
    5 26250314066
    439986238782 581370817372 409476934981 287439719777 737637983182
    5 616753575719
    321037808624 222034505841 214063039282 441536506916 464097941819
    5 431813672576
    393004301966 405902283416 900951084746 672201172466 518769038906
    

    输出:

    3
    1
    4
    -1
    -1
    0
    3119
    28999960732
    -1
    

    与题目要求一致。


    总结

    本题通过变换 x=xkx' = x - k 将操作转化为简单的分裂(和不变),然后利用整除性和最大公因数求解。关键在于判断所有 aika_i - k 必须同号且非零,此时最优的最终值由它们的最大公因数决定。最终操作次数即为总份数减去初始个数。

    • 1

    信息

    ID
    6420
    时间
    1000ms
    内存
    256MiB
    难度
    8
    标签
    递交数
    1
    已通过
    1
    上传者