计蒜客 蒜头君的数轴
不考虑某个区间,其他区间必须距离相等,也就是要划分为距离为最大公约数。
那么如何快速求解任意$n-1$个区间的最大公约数?用l[i]表示前i个数的最大公约数,r[i]表示后$(n-i)$个区间的最大公倍数,删除区间i之后剩余的$n-1$个区间的最大公约数就是$gcd(l[i-1], r[i+1])$
AC代码
#include <stdio.h> #include <algorithm> using namespace std; typedef long long LL; const int maxn = 100000 + 5; int x[maxn], dis[maxn]; int l[maxn], r[maxn]; int gcd(int a, int b) { return b == 0 ? a : gcd(b, a%b); } int main() { int n; while(scanf("%d", &n) == 1) { for(int i = 0; i < n; i++) { scanf("%d", &x[i]); } if(n <= 3) { printf("0\n"); continue; } sort(x, x+n); LL sum_dis = 0; for(int i = 1; i < n; i++) { dis[i-1] = x[i] - x[i-1]; sum_dis += dis[i-1]; } LL ans = 1e18; n -= 1; l[0] = dis[0]; for(int i = 1; i < n; i++) { l[i] = gcd(l[i-1], dis[i]); } r[n-1] = dis[n-1]; for(int i = n-2; i >= 0; i--) { r[i] = gcd(r[i+1], dis[i]); } //删除最左端距离 ans = min(ans, (sum_dis-dis[0])/r[1] - (n-1)); //删除最右端距离 ans = min(ans, (sum_dis-dis[n-1])/l[n-2] - (n-1)); //删除[1,n-2] for(int i = 1; i <= n-2; i++) { ans = min(ans, (sum_dis - dis[i])/gcd(l[i-1], r[i+1]) - (n-1)); } printf("%lld\n", ans); } return 0; }
如有不当之处欢迎指出!