1. 程式人生 > >CF刷題-Codeforces Round #481-D. Almost Arithmetic Progression

CF刷題-Codeforces Round #481-D. Almost Arithmetic Progression

題目連結: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;
}