给你n个数的坐标(只有x轴),求最小移动几个数使之变成等差数列。
首先可以想到一定有两个数是不动的。
如果起点不是不动的,是移动过来的,那么移动到最后是等价的。
所以枚举起点 i 和 另外一个不动点 j ,再枚举 i-j 之间有几个数移动过来,
这样就可以得出d。根据起点a[i],和等差d,可以知道整个序列。
#include<iostream>
#include<cstdio>
#include<map>
#include<algorithm>
using namespace std;
const int N=42;
#define rep(i,b,e) for(int i=b;i<e;i++)
typedef long long LL;
int n;
LL a[N];
map<LL,int> mp;
int solve(){
if(n<=2) return 0;
sort(a,a+n);
int ans=n-2;
//***讨论间隔不为0的情况***
rep(i,0,n){//枚举第1点i
rep(j,i+1,n){//枚举固定点j
if(a[i]==a[j]) continue;
rep(k,0,n-2){//i,j之间有k个点
if((a[j]-a[i])%(k+1)!=0) continue;
LL d=(a[j]-a[i])/(k+1);
LL now=a[i];//枚举超int wa
int cnt=0;
rep(p,0,n){
if(mp[now]==0) cnt++;
now+=d;
}
ans=min(ans,cnt);
}
}
}
//***讨论间隔为0的情况*** wa
int cnt=1;
rep(i,1,n){
if(a[i]==a[i-1]) cnt++;
else{
ans=min(ans,n-cnt);
cnt=1;
}
}
return ans;
}
int main(){
int tt,cas=1;
for(cin>>tt;cas<=tt;cas++){
cin>>n;
mp.clear();
for(int i=0;i<n;i++){
cin>>a[i];
mp[a[i]]++;
}
printf("Case #%d: %d\n",cas,solve());
}
return 0;
}
/*
1
4
1 1 1 3
*/