D. Almost Arithmetic Progression
description:
给出一个长度为n的数列,每个数最多可以操作一次,问最少操作多少次能把它变成等差数列。操作内容为,将一个数加一或者减一。
input:
第一行n
之后一行为n个数代表数列
output:
一个整数代表最少的操作次数
analysis:
解题很重要的一点是,题目的条件要用好,很多时候问题的条件就是突破口,如果题目要求要达成什么样的条件,不妨先假设已经达到了什么样的条件,然后再继续往前看看有什么发现。
比如这里要充分用好等差数列这个的条件。因为是等差数列,所以只要前两项就确定了唯一的数列。这样就可以枚举数列前两项再计算该数列的对应的操作次数,更新答案即可。
代码:
#include<iostream> #include<string> #include<cstring> #include<vector> #include<stack> #include<algorithm> #include<map> #include<set> #include<queue> #include<sstream> #include<cmath> #include<iterator> #include<bitset> #include<stdio.h> using namespace std; #define _for(i,a,b) for(int i=(a);i<(b);++i) #define _rep(i,a,b) for(int i=(a);i<=(b);++i) typedef long long LL; LL readint() { LL x; scanf("%lld",&x); return x; } const int INF = 1 << 30; const int maxn = 100005; int n; int a[maxn]; int a1[maxn]; int cnt,ans; void solve(){ int d=a1[1]-a1[0]; for(int i=2;i<n;++i){ int x=a1[i]-(a1[i-1]+d); if(abs(x)>1){return;} else { if(x!=0)cnt++; a1[i]=a1[i-1]+d; } } ans=min(ans,cnt); } int main() { //freopen("C:\\Users\\admin\\Desktop\\in.txt", "r", stdin); //freopen("C:\\Users\\admin\\Desktop\\out.txt", "w", stdout); while(~scanf("%d",&n)){ for(int i=0;i<n;++i)scanf("%d",&a[i]); ans=INF; if(n==1||n==2){ printf("0\n"); } else { for(int dx=-1;dx<=1;++dx) for(int dy=-1;dy<=1;++dy){ memcpy(a1,a,sizeof(a)); a1[0]+=dx;a1[1]+=dy; cnt=abs(dx)+abs(dy); solve(); } if(ans==INF)printf("-1\n"); else printf("%d\n",ans); } } return 0; }