题意:一个数字序列,可以随意排列,可进行如下操作:将一个数加一或减一,问至少需要多少次操作使得arr[i]=ci(i从0开始)
首先要将数列从小到大排列,因为ci是递增的.当个数小于等于二时,arr[0]变为1是固定的,如果有arr[1],那么令c为arr[1]即可,所以此时的答案为arr[0]-1。当n大于二时,我做题的时候考虑的是答案是否在arr[n-1](1/n)附近,因为当次幂越大,偏差的值也会越大,当如果只有arr[n-1]近,但其他数都离xi比较远时显然此方案错误,思来想去只能想到暴力,但我又考虑怎么确定答案的范围呢,小于arr[n-1]显然是不现实的,发现当从小到大遍历时,遍历的值越接近答案,那么需要操作的次数一定会减小,所以遍历的终止条件是需要的操作次数大于上一遍历值下的操作次数。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<vector>
#include<map>
#include<queue>
#include<cmath>
using namespace std;
typedef long long ll;
const int N = 1e5 + 100;
ll arr[N];
ll sum = 0;
ll ans = 1e18;
int main() {
ll n;
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> arr[i];
}
sort(arr + 1, arr + 1 + n);
if (n <= 2) {
cout << arr[1] - 1 << endl;
return 0;
}
for (ll i = 1; i < 1e9 + 10; i++) {
ll temp = 1;
ll t_ans = arr[1] - 1ll;
bool sign = false;
for (ll j = 2; j <= n; j++) {
temp = temp * i;
t_ans = t_ans + abs(arr[j]-temp);
if (t_ans > ans) {//注意要及时推出,否则可能会溢出
sign = true;
break;
}
}
if (sign) break;
ans = min(ans, t_ans);
}
cout << ans << endl;
}