链接
传送门
分析
这道B题还是有点点难度的,不算很简单。首先如果说每个数都相同的话就不用操作了。如果需要操作,那么什么时候不行呢?如果说里面有一个1就无法操作了,因为什么数除1都不会改变,1被除的就会变成零,最后一个总有一个值不是零。那么如果说没有1呢?那么我们首先找到最小值,让后遍历这个数组,如果说这个数比这个数大除完之后一定大于等于2,如果说除完之后比minn要小了,更新minn,使得minn永远是数组中的最小值,因为大数除小数并且向上取整,必定大于等2,不会出现1,每次必定减小,所以不会出现死循环。因为减少量的贡献是至少是除2,减少量至少是2,但是增加量贡献最多是1。例如,5 / 2 = 2.5 = 3,整数部分5 整除 2 等于2减少了3,如果还有小数部分+1,记作a / b = c, 前者写成 k b + r 整除 b ->k, r / b 向上取整,对于前者的减少贡献量是(b - 1) * k,b>=2,k>= 2,所以减少量大于等于2,完毕。
实现
#include <bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
using namespace std;
const int N = 105, p = 1e9 + 7;
typedef pair<int, int> PII;
int a[N];
int n;
bool check() {
for (int i = 1; i <= n; i++) {
if (a[i] != a[1]) return 1;
}
return 0;
}
void solve() {
cin >> n;
int minn = inf, p;
for (int i = 1; i <= n; i++) {
cin >> a[i];
if (a[i] < minn) {
minn = a[i];
p = i;
}
}
if (!check()) {
cout << 0 << '\n';
return;
}
if (minn == 1) {
cout << -1 << '\n';
return;
}
vector<PII> ans;
while (check()) {
for (int i = 1; i <= n; i++) {
while (a[i] > minn) a[i] = (a[i] + minn - 1) / minn, ans.push_back({i, p});//这里是向上取整的一种写法
if (a[i] < minn) minn = a[i], p = i;
}
}
cout << ans.size() << '\n';
for (auto x : ans) {
cout << x.first << ' ' << x.second << '\n';
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
int T = 1;
cin >> T;
while (T--) solve();
}