计蒜客

我感觉出的很好的一道题,首先不难想到(其实我刚开始没想到),加点的个数就是找已有点两两形成区间的gcd,那么问题就出在了复杂度上,每次循环哪个区间不要复杂度过高,所以运用正反两次前缀和(?好像不能这么叫)预处理一下就可以O(n)搞定了,说一下有一个让我找了一年的bug吧,我把ans的初始值设的太小,导致WA,最后改成了2147483645之后就快乐AC了

#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 100010;
int a[N], f[N], d[N];
int gcd(int a, int b) {
    if (a < b)    swap(a, b);    
    return (a % b == 0) ? b : gcd(b, a % b);
}
int main() {
    int n;
    scanf("%d", &n);
    for (int i = 0; i < n; i++)
        scanf("%d", &a[i]);
    sort(a, a + n);
    int sum = a[n - 1] - a[0];
    f[1] = a[1] - a[0];
    for (int i = 2; i < n; i++)
        f[i] = gcd(a[i] - a[i - 1], f[i - 1]);
    d[n - 2] = a[n - 1] - a[n - 2];
    for (int i = n - 3; i >= 0; i--)
        d[i] = gcd(a[i + 1] - a[i], d[i + 1]);
    int ans = 2147483645;
    ans = min(ans, (sum - a[1] + a[0]) / d[1] + 2 - n);
    ans = min(ans, (sum - a[n - 1] + a[n - 2]) / f[n - 2] + 2 - n);
    for (int i = 1; i < n - 2; i++) {
        ans = min((sum - (a[i + 1] - a[i])) / gcd(f[i], d[i + 1]) + 2 - n, ans);
    }
    printf("%d
", ans);
    return 0;
}
原文地址:https://www.cnblogs.com/cminus/p/11991683.html