解法其实很简单,但是自己写的太挫了,然后就FST了。
题意:给定一个长为n的序列,每个数字只能+1,不变,-1三个操作,问最少用多少次操作可以将序列凑为一个等差序列。
解法:首先跑一遍整个序列,找到相邻两个序列之差的最大值和最小值。很明显,如果最大值和最小值之间的差值大于4肯定是怎样变化都无解的。如果差值小于4的话,我们从差值的最小值向最大值枚举即可。比如差值为10,那么我们再枚举第一个数的三种情况(+1,不变,-1),那么后面的序列都是确定的,查看是否有不满足情况的地方即可。如果没有,则更新答案。复杂度O(4 * 3 * n)
代码如下:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5;
const int INF = 0x3f3f3f3f;
int n, nn, a[maxn], c[maxn], ans = INF;
int Max = -INF, Min = INF;
int dfs(int p) {
int cnt = 0, myans = INF;
bool ok = 0;
for(int i = -1; i <= 1; i++) {
ok = 0;
c[0] = a[0] + i;
cnt = abs(i);
for(int j = 1; j < n; j++) {
c[j] = c[j - 1] + p;
int tmp = abs(c[j] - a[j]);
if(tmp > 1) {
ok = 1;
break;
} else {
cnt += tmp;
}
}
if(ok)
continue;
myans = min(myans, cnt);
}
return myans;
}
int main() {
ios::sync_with_stdio(0);
cin >> n;
if(n == 1) {
cout << 0 << endl;
return 0;
}
for(int i = 0; i < n; i++)
cin >> a[i];
nn = n - 1;
for(int i = 0, tmp; i < nn; i++) {
tmp = a[i + 1] - a[i];
if(Max < tmp)
Max = tmp;
if(Min > tmp)
Min = tmp;
}
if(Max - Min > 10) {
cout << -1 << endl;
return 0;
}
for(int i = Min; i <= Max; i++) {
ans = min(dfs(i), ans);
}
if(ans != INF)
cout << ans << endl;
else
cout << -1 << endl;
return 0;
}