• 程序设计:蒜头君的数轴 (前缀和➕gcd)


    今天蒜头君拿到了一个数轴,上边有 nn 个点,但是蒜头君嫌这根数轴不够优美,想要通过加一些点让它变优美,所谓优美是指考虑相邻两个点的距离,最多只有一对点的距离与其它的不同。

    蒜头君想知道,他最少需要加多少个点使这个数轴变优美。

    输入格式

    输入第一行为一个整数 n(1 leq n leq 10^5)n(1n105),表示数轴上的点数。

    第二行为 nn 个不重复的整数 x_1,x_2,...,x_n(-10^9 leq x_i leq 10^9)x1,x2,...,xn(109xi109),表示这些点的坐标,点坐标乱序排列。

    输出格式

    输出一行,为一个整数,表示蒜头君最少需要加多少个点使这个数轴变优美。

    样例输入

    4
    1 3 7 15

    样例输出

    1

    思路:

    如果不考虑可以有一个区间不同,让我们求的是所有的区间都要优美。至少需要多少个点?

    很简单,我们就去求所有区间长度的gcd  求得的gcd就是最小区间长度

    考虑最多只有一对点的距离与其他的不同,即此时我们可以去除一个间隔求出 gcd,那么现在我们要去除哪一个间隔才能使得加点的个数最小呢?

    假设某相邻两点之间的距离为 x ,此时我们加点的目标间隔为 gcd,那么显然我们需要在这两点之间增加 x/gcd−1个点。

    综上得出结论,我们期望的 gcd 越大越好,因为这样加点的个数会越小。

    pos[i]代表去除第 i 个间隔以后的 gcdgcd ,显然它可以通过前缀 gcd 与后缀 gcd 配合求出。

    随后我们找出 pos 中的最大值,设为 maxx ,则 maxx 为解的最优间隔,枚举所有相邻两点的距离,求解需要加点的个数。

    可能会出现两种情况:

    一、某个区间长度不可以分成符合gcd的倍数的形式。那其实就说明我们去除的就是这个区间。 比如 1,4,4,8 ,8     它的maxx = gcd(4,4,8,8) = 4   那么第一个区间长度1 肯定被去除了

    二、所有区间都可以分成符合gcd的倍数的形式。那么我们就去除需要分成份数最多的。 比如4,4,4,8,8   它的maxx  = gcd(4,4,4,8,8) = 4  所有区间都可以分成4的倍数,那么我们就去除分成份数最多的区间 8

     1 #include <iostream>
     2 #include <algorithm>
     3 #include <stdlib.h>
     4 #include <string>
     5 #include <string.h>
     6 #include <set>
     7 #include <queue>
     8 #include <stdbool.h>
     9 
    10 #define LL long long
    11 using namespace std;
    12 const int MAXN=100005;
    13 
    14 int leftt[MAXN],rightt[MAXN],pos[MAXN];
    15 int a[MAXN],b[MAXN];
    16 int n;
    17 
    18 int gcd(int a,int b)
    19 {
    20     int t;
    21     while (b)
    22     {
    23         t = b;
    24         b = a%b;
    25         a = t;
    26     }
    27     return a;
    28 }
    29 
    30 int main()
    31 {
    32 #ifndef ONLINE_JUDGE
    33     freopen("../in.txt","r",stdin);
    34 #endif
    35     scanf("%d",&n);
    36     for (int i=0;i<n;i++)
    37         scanf("%d",&a[i]);
    38     sort(a,a+n);
    39     for (int i=1;i<n;i++)
    40         b[i] = a[i]-a[i-1];
    41     leftt[1] = b[1];
    42     for (int i=2;i<n;i++)
    43     {
    44         leftt[i] = gcd(leftt[i-1],b[i]);
    45     }
    46     rightt[n-1] = b[n-1];
    47     for (int i=n-2;i>0;i--)
    48     {
    49         rightt[i] = gcd(b[i],rightt[i+1]);
    50     }
    51     pos[1] = rightt[2];
    52     pos[n-1] = leftt[n-2];
    53     for (int i=2;i<n-1;i++)
    54         pos[i] = gcd(leftt[i-1],rightt[i+1]);
    55     int maxx = pos[1];
    56     for (int i=2;i<n;i++)
    57     {
    58         if (pos[i]>maxx)
    59             maxx = pos[i];
    60     }
    61     int ans = 0,ms = 0,cnt = 0;
    62     for (int i=1;i<n;i++)
    63     {
    64         if (b[i]%maxx != 0)
    65         {
    66             cnt++;
    67             continue;
    68         }
    69         ans += b[i]/maxx - 1;
    70         ms = max(ms,b[i]/maxx-1);
    71     }
    72     if (!cnt)
    73         ans -= ms;
    74     cout << ans << endl;
    75     return 0;
    76 }
  • 相关阅读:
    24张图,九大数据结构安排得明明白白
    mysql中的mvcc解读
    常见电商项目的数据库表设计(MySQL版)
    两万字深度介绍分布式系统原理,一文入魂
    使用消息中间件时,如何保证消息仅仅被消费一次?
    GCC/G++选项 -Wl,-Bstatic和-Wl,-Bdynamic
    sql 练习
    设计模式-单例模式
    设计模式-抽象工厂模式
    设计模式-工厂方法模式
  • 原文地址:https://www.cnblogs.com/-Ackerman/p/11217795.html
Copyright © 2020-2023  润新知