程序设计:蒜头君的数轴 计蒜客 - A1633

原题链接

考察:GCD+前缀和思想

根据题意,最多允许一个区间和其他区间的距离不一样.因此在计算的时候我们需要去掉那个区间.那么剩下的区间取多大呢?可以发现:剩下区间要求的长度一定为它们的最小公倍数.这样才能凑得相等.假设剩下区间要求长度为k,区间需要增加的点数为len/k-1.因此最小的点数就是k尽量大

接下来是几个要解决的问题

1.如何在时间范围内求出剩下的最小公倍数

答: 我们可以利用前缀和思想.gcdl[i]存储1~i的区间的最小公倍数,gcdr[i]存储i~n的最小公倍数,去掉某个区间的剩下的公倍数就是由两个再次求gcd.

2.如何计算答案?

答:求出去掉每个区间的最小公倍数后,我们尽量取最大值,会有两种情况:

  1. 去掉的区间不能整除最大值.因此计算的时候不能算入其中
  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 }

 

posted @ 2021-01-17 22:24  acmloser  阅读(65)  评论(0编辑  收藏  举报