程序设计:蒜头君的数轴 计蒜客 - A1633
考察:GCD+前缀和思想
根据题意,最多允许一个区间和其他区间的距离不一样.因此在计算的时候我们需要去掉那个区间.那么剩下的区间取多大呢?可以发现:剩下区间要求的长度一定为它们的最小公倍数.这样才能凑得相等.假设剩下区间要求长度为k,区间需要增加的点数为len/k-1.因此最小的点数就是k尽量大
接下来是几个要解决的问题
1.如何在时间范围内求出剩下的最小公倍数
答: 我们可以利用前缀和思想.gcdl[i]存储1~i的区间的最小公倍数,gcdr[i]存储i~n的最小公倍数,去掉某个区间的剩下的公倍数就是由两个再次求gcd.
2.如何计算答案?
答:求出去掉每个区间的最小公倍数后,我们尽量取最大值,会有两种情况:
- 去掉的区间不能整除最大值.因此计算的时候不能算入其中
- 去掉的区间也能整除最大值.因此答案要去掉的区间是增加点数最多的区间
以上即可求出答案
1 #include <iostream> 2 #include <algorithm> 3 using namespace std; 4 typedef long long ll; 5 const int N = 1e5+10; 6 int n,b[N],a[N],gcdl[N],gcdr[N],ans[N]; 7 int gcd(int a,int b) 8 { 9 return b?gcd(b,a%b):a; 10 } 11 int main() 12 { 13 int maxn = -1,idx = -1,len = -1; ll res = 0; 14 scanf("%d",&n); 15 for(int i=1;i<=n;i++) scanf("%d",&a[i]); 16 sort(a+1,a+n+1); 17 for(int i=1;i<=n;i++) b[i] = a[i]-a[i-1]; 18 gcdl[2] = b[2],gcdr[n-1] = b[n]; 19 for(int i=3;i<=n;i++) gcdl[i] = gcd(gcdl[i-1],b[i]); 20 for(int i=n-2;i>0;i--) gcdr[i] = gcd(gcdr[i+1],b[i+1]); 21 ans[1] = gcdr[2]; ans[n-1] = gcdl[n-1]; 22 for(int i=2;i<=n-2;i++) ans[i] = gcd(gcdl[i],gcdr[i+1]); 23 for(int i=1;i<=n-1;i++) maxn = max(maxn,ans[i]); 24 for(int i=2;i<=n;i++) 25 { 26 if(b[i]%maxn!=0) { idx = i;continue; } 27 res+=(ll)b[i]/maxn-1; 28 len = max(b[i],len); 29 } 30 if(idx==-1) res-=len/maxn-1; 31 printf("%lld\n",res); 32 return 0; 33 }