计蒜客 蒜头君的数轴

不考虑某个区间,其他区间必须距离相等,也就是要划分为距离为最大公约数。

那么如何快速求解任意$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
");
            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
", ans);
    } 
    return 0;
}

如有不当之处欢迎指出!

原文地址:https://www.cnblogs.com/flyawayl/p/8659044.html