CodeFroces 978D. Almost Arithmetic Progression

解法其实很简单,但是自己写的太挫了,然后就FST了。

题意:给定一个长为n的序列,每个数字只能+1,不变,-1三个操作,问最少用多少次操作可以将序列凑为一个等差序列。

解法:首先跑一遍整个序列,找到相邻两个序列之差的最大值和最小值。很明显,如果最大值和最小值之间的差值大于4肯定是怎样变化都无解的。如果差值小于4的话,我们从差值的最小值向最大值枚举即可。比如差值为10,那么我们再枚举第一个数的三种情况(+1,不变,-1),那么后面的序列都是确定的,查看是否有不满足情况的地方即可。如果没有,则更新答案。复杂度O(4 * 3 * n)

代码如下:

#include
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;
}

你可能感兴趣的:(暴力求解,枚举)