1. 程式人生 > >CodeFroces 978D. Almost Arithmetic Progression

CodeFroces 978D. Almost Arithmetic Progression

解法其實很簡單,但是自己寫的太挫了,然後就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;
}