CF刷題-Codeforces Round #481-D. Almost Arithmetic Progression
阿新 • • 發佈:2018-12-27
題目連結:https://codeforces.com/contest/978/problem/D
題解:
題目的大意就是:這組序列能否組成等差數列?一旦構成等差數列,等差數列的公差必定確定,而且,對於給定的數列,公差的可能性是已知的。
我的解決思路是:對於給定的數列,最後一位數 - 第一位數 / (n -1) 必定是公差,而對於我們要判斷的原數列,其最後一位 - 第一位數的值是可以-2,-1,0,+1,+2的,窮舉可能性一切公差,找出變動最小的情況。程式碼如下(有點小複雜,沒優化):
#include<cstdio> #include<cstring> #include<algorithm> #include<map> #include<iostream> #include<vector> #include<string> #include<cmath> #include<set> using namespace std; typedef long long ll; typedef unsigned long long ull; const int N = 100000+5; int ini[N]; int ans[N]; int tofopr; set<int> jg;int isok(int n,int newc){ int c = ans[1]; int t = 0; for(int i = 2;i<=n - 1;i++){ c+= newc; if(abs(ini[i] - c) > 1) return -1; if(ini[i] != c){ t++; } } return t; } int main(void){ int n; jg.clear(); scanf("%d",&n);if(n <= 2){ int b; for(int i = 1;i<=n;i++){ scanf("%d",&b); } printf("0\n"); } else{ int b; for(int i = 1;i<=n;i++){ scanf("%d",&b); ini[i] = b; } int c = ini[n] - ini[1]; int start,end; for(int i = c -2;i<=c+2;i++){ tofopr = 0; if(i%(n-1) == 0){ int newc = i / (n - 1); if(i == c - 2){ start = ini[1] + 1; end = ini[n] - 1; if(end >= 0){ ans[1] = start; ans[n] = end; tofopr = isok(n,newc); if(tofopr >= 0){ tofopr += 2; jg.insert(tofopr); } } } if(i == c -1){ start = ini[1]; end = ini[n] - 1; if(end >= 0){ ans[1] = start; ans[n] = end; tofopr = isok(n,newc); if(tofopr >= 0){ tofopr += 1; jg.insert(tofopr); } } start = ini[1] + 1; end = ini[n]; ans[1] = start; ans[n] = end; tofopr = isok(n,newc); if(tofopr >= 0){ tofopr += 1; jg.insert(tofopr); } } if(i == c){ start = ini[1]; end = ini[n]; ans[1] = start; ans[n] = end; if(tofopr >= 0){ tofopr = isok(n,newc); jg.insert(tofopr); } } if(i == c + 1){ start = ini[1] -1; end = ini[n]; if(start >= 0){ ans[1] = start; ans[n] = end; tofopr = isok(n,newc); if(tofopr >= 0){ tofopr += 1; jg.insert(tofopr); } } start = ini[1]; end = ini[n]+1; ans[1] = start; ans[n] = end; tofopr = isok(n,newc); if(tofopr >= 0){ tofopr += 1; jg.insert(tofopr); } } if(i == c + 2){ start = ini[1] - 1; end = ini[n] + 1; if(start >= 0){ ans[1] = start; ans[n] = end; tofopr = isok(n,newc); if(tofopr >= 0){ tofopr += 2; jg.insert(tofopr); } } } } } if(jg.empty()){ printf("-1"); } else { auto it = jg.begin(); printf("%d",*it); } } return 0; }
而神犇的程式碼如下,思路是一致的,但是神犇找最小的方法很特殊!程式碼如下:
#include <bits/stdc++.h> using namespace std; const int maxn = 2e5 + 100; typedef long long ll; ll n, num[maxn]; void init() { scanf("%lld", &n); for (int i = 0; i < n; i++) scanf("%lld", &num[i]); } ll get_ans(ll tol) { ll cnt[3],st; cnt[0] = cnt[1] = cnt[2] = 0; for(int i=0;i<3;i++) { if(i == 0) st = num[0]-1; else if(i == 1) st = num[0]; else st = num[0] + 1; for (ll j = 0; j < n; j++) { if(abs(num[j]-st) > 1) { cnt[i] = INT_MAX; break; } cnt[i] += abs(num[j] - st); st += tol; } } if(cnt[0] == cnt[1] && cnt[1] == cnt[2] && cnt[0] == INT_MAX) //無法組成等差數列返回-1 return -1; return min(cnt[0], min(cnt[1], cnt[2])); } int main() { init(); ll Min = INT_MAX,tol; tol = num[1]-num[0]; ll ans = get_ans(tol); if(ans >= 0) Min = min(Min, ans); for (int i = 1; i <= 2; i++) { ans = get_ans(tol-i); if (ans >= 0) Min = min(Min, ans); ans = get_ans(tol+i); if (ans >= 0) Min = min(Min, ans); } if (Min == INT_MAX) printf("-1"); else printf("%lld", Min); return 0; }