gcd前缀和-蒜头君的数轴
题目:
今天蒜头君拿到了一个数轴,上边有 n个点,但是蒜头君嫌这根数轴不够优美,想要通过加一些点让它变优美,所谓优美是指考虑相邻两个点的距离,最多只有一对点的距离与其它的不同。
蒜头君想知道,他最少需要加多少个点使这个数轴变优美。
输入格式
输入第一行为一个整数n(1≤n≤10^5),表示数轴上的点数。
第二行为 nn 个不重复的整数 x1,x2,...,xn(−10^9≤xi≤10^9),表示这些点的坐标,点坐标乱序排列。
输出格式
输出一行,为一个整数,表示蒜头君最少需要加多少个点使这个数轴变优美。
主要思路是求:最大公约数。
由题意可以知道,数轴是否优美与相邻两个点的距离有关,假设我们暂时不考虑最多只有一对点的距离与其他的不同,那么最终我们加完点之后的间隙大小便等于此时所有间隔的 gcd,于是我们可以求出间隔 gcd,然后此时相邻两个点之间所要添加的点的个数便可以直接计算得到了。
n个数,互不相同,则求相邻两点距离,共有n-1个距离。题目允许最多有一对点距离与其他不同,因此对于n-1个距离,我们都要考虑到,因此要对n-1个距离逐个删去,对剩余n-2个距离求共同的最大公约数。为了求得这个最大公约数。则解法如下:
1.如果n<=3,则不需要考虑题中操作就满足题目要求,答案为0.
2.除情况1外的其他情况。
设置gcd1[i]:表示前i个距离求得的公共最大公约数。
设置gcd2[i],表示后i个距离求得的公共最大公约数。
则考虑逐个删除某个距离,假设当前删除第i个距离。
若i = 1,即删除第一个距离,则需要后n-2个距离的最大公约数,即gcd2[n-2].
若i = n-1,即删除最后一个距离,则需要前n-2个距离的最大公约数,即gcd1[n-2].
若i > 1 && i < n-1,则需要前i-1个距离的最大公约数和后n-1-i个距离的最大公约数 和在一起求出最大公约数。即gcd(gcd1[i-1],gcd2[n-i-1]).
转载自博客:https://blog.csdn.net/HTallperson/article/details/79769181
代码:
#include<cstdio> #include<iostream> #include <algorithm> using namespace std; const int maxn = 1e5+10; int gcd1[maxn]; //gcd1[i]是前i个距离的gcd int gcd2[maxn]; //gcd2[i]是后i个距离的gcd int arr[maxn]; long long dist[maxn]; int gcd(int a,int b) { if(b==0) return a; else return gcd(b,a%b); } int main() { int n;scanf("%d",&n); for(int i=0;i<n;i++){ scanf("%d",&arr[i]); } if(n<=3){ printf("0\n"); } else{ sort(arr,arr+n); long long sum=0; for(int i=1;i<n;i++){ dist[i]=arr[i]-arr[i-1]; sum+=dist[i]; } int d=dist[0]; for(int i=1;i<n;i++){ d=gcd(d,dist[i]); gcd1[i]=d; } d=dist[n-1]; for(int i=1;i<n;i++){ d=gcd(d,dist[n-i]); gcd2[i]=d; } int Min=0x3f3f3f3f,temp; for(int i=1;i<n;i++){ if(i==1){ temp=(sum-dist[i])/gcd2[n-2]; }else if(i==n-1){ temp=(sum-dist[i])/gcd1[n-2]; }else{ temp=(sum-dist[i])/gcd(gcd1[i-1],gcd2[n-i-1]); } Min=min(Min,temp-(n-2)); } printf("%d\n",Min); } return 0; }