1 条题解
-
0
D. Split Plus K 题解
问题描述
黑板上有 个正整数 ,给定正整数 。每次操作:选择一个数 ,擦掉它,写上两个正整数 满足 。问能否通过若干次操作使得所有数相等,并求出最少操作次数。
关键变换
令 ,将原问题中的每个数都减去 。
$$(y'+k)+(z'+k) = (x'+k)+k \;\Longrightarrow\; y' + z' = x'. $$
原操作 变为:于是变换后的问题等价于:
初始有 个数 ,每次操作选择一个数 ,擦掉它,写上两个数 满足 。
目标:使所有数相等(记为 ),且原数 必须为正整数。
操作次数 = 最终数的个数 - 初始个数 。
数学模型
设最终所有数变为 (原问题),对应 。
对初始的 ,设它经过 次操作后变成 个 。每次操作总和增加 ,因此:令 ,则 ,代入得:
$$a_i - k = (p_i+1) d \;\Longrightarrow\; a_i' = q_i d, $$其中 为正整数。
最终数的总个数为 ,初始有 个数,所以操作次数为:这里 必须整除每一个 ,且 (若 则所有 ,单独处理)。
同时 必须成立,即 。由于 ,当 为负数且绝对值很大时可能破坏正性,但下面将证明只需考虑 与 同号的情况。
可行性分析
- 若所有 ,即所有 ,则已经全等,答案为 。
- 否则, 必须非零。由于 ,所有 必须同号(全正或全负),否则不可能同时被同一个非零 整除且 为正整数。
- 若存在某个 而其他非零,则 要求 或 ,前者矛盾,后者不可能(),因此无解。
所以可行当且仅当:
- 所有 全为正,或全为负,且没有零。
最小化操作次数
当所有 同号时,取 为它们的最大公因数(带符号)能使 最小(因为 越大,每个商越小)。
设 ,则:- 若所有 ,取 ;
- 若所有 ,取 (此时 为正整数)。
此时操作次数为:
注意当所有 已经相等(且不等于 )时, 全相等非零,,代入得 ,符合预期。
正确性补充说明
- 当 时,,则最终数 ,且每次分裂得到的 在原问题中为 ,因为 ,所以 ,均为正整数,符合要求。
- 当 时,,则 。由于 ,故 ,而 整除 ,可能使 很小甚至非正?实际上,由 ,,,得 ,故 ,所以 $m = k - g \ge k - |a_i'| \ge k - (k - a_i) = a_i > 0$,因此 仍为正整数。同时分裂出的 在原问题中为 ,由于 ,故 ,而 ,所以新写的数比原来的大,但仍是正整数,符合操作要求。
算法步骤
- 读入 和数组 。
- 计算 。
- 若所有 ,输出 。
- 若存在 或 有正有负,输出 。
- 否则,计算 。
- 输出 。
复杂度 ,满足题目限制。
代码实现(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与题目要求一致。
总结
本题通过变换 将操作转化为简单的分裂(和不变),然后利用整除性和最大公因数求解。关键在于判断所有 必须同号且非零,此时最优的最终值由它们的最大公因数决定。最终操作次数即为总份数减去初始个数。
- 1
信息
- ID
- 6420
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 8
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者