思路:
首先考虑到要满足除了一对点的距离,其余的相邻两点间的距离要相等,那么最后这个距离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; }