CodeFroces 978D. Almost Arithmetic Progression
阿新 • • 發佈:2019-01-11
解法其實很簡單,但是自己寫的太挫了,然後就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; }