思路:
首先考虑到要满足除了一对点的距离,其余的相邻两点间的距离要相等,那么最后这个距离r一定要是原本相邻点距离的公约数,且一定是最大公约数才最优.
n个点n-1个距离,每次去掉一个, 那么如何求每次去掉一个剩下n-2个距离的gcd呢?
由于gcd的非递增性质,也就是 a,b,c三个数的gcd = __gcd(__gcd(a,b),c).我们可以正向维护一个lgcd前缀,逆向维护一个rgcd前缀,当去掉某个距离i时,此时剩下距离的gcd为
gcd = __gcd(lgcd[i-1],rgcd[i+1])。
注意处理两头的情况
#include <bits/stdc++.h>
#define pb push_back
#define inf 0x3f3f3f3f
typedef long long ll;
using namespace std;
const int maxn = 1e5+5;
int x[maxn],n;
int dis[maxn];
int lgcd[maxn],rgcd[maxn];
ll sum[maxn];
int main()
{
while(~scanf("%d",&n))
{
for(int i = 1;i <= n;++i)
scanf("%d",&x[i]);
if(n <= 3)
{
puts("0");
continue;
}
sort(x + 1,x + 1 + n);
sum[0] = 0;
for(int i = 1;i < n;++i)
{
dis[i] = x[i + 1] - x[i];
sum[i] = sum[i - 1] + dis[i];
}
lgcd[1] = dis[1],rgcd[n - 1] = dis[n - 1];
for(int i = 2;i < n;++i)
lgcd[i] = __gcd(lgcd[i - 1],dis[i]);
for(int i = n - 2;i >= 1;--i)
rgcd[i] = __gcd(rgcd[i + 1],dis[i]);
int mi = inf;
for(int i = 1;i < n;++i)
{
int ox = inf;
if(i == 1)
{
ox = (sum[n - 1] - dis[i]) /rgcd[2];
}
else if(i == n - 1)
{
ox = sum[n - 2]/lgcd[n - 2];
}
else
{
int gcd = __gcd(lgcd[i-1],rgcd[i + 1]);
ox = (sum[n - 1] - dis[i]) / gcd;
}
mi = min(mi,ox - (n - 2));
}
printf("%d\n",mi);
}
return 0;
}