题目链接: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 "); } 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; }