我感觉出的很好的一道题,首先不难想到(其实我刚开始没想到),加点的个数就是找已有点两两形成区间的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\n", ans); return 0; }