找出无法形成的最小金额

时间:2015-01-02 18:08:29

标签: algorithm minimum

给出从1到N的正整数,其中 N可以达到10 ^ 9 。缺少来自这些给定整数的一些K个整数。 K最多可以是10 ^ 5个元素。我需要找到能够以有效的方式从剩余的N-K元素中形成的最小总和。

实施例;假设我们有N = 5,这意味着我们有{1,2,3,4,5}并且让K = 2而缺少的元素是:{3,5}那么剩下的数组现在是{1,2,4}最小值不能从这些剩余元素形成的总和为8,因为:

1=1
2=2
3=1+2
4=4
5=1+4
6=2+4
7=1+2+4

那么如何找到这个不可归小的最小值?

如果我可以通过这种方法存储所有剩余的元素,我知道如何找到它:

我们可以使用类似于Eratosthenes筛子的东西,用于寻找素数。同样的想法,但为不同的目的有不同的规则。

  1. 将数字从0存储到所有数字的总和,并交叉关闭0.
  2. 然后一次取一个号码,无需更换。
  3. 当我们取数字Y时,然后将每个Y加上一些先前交叉的数字交叉。
  4. 当我们为剩下的每个号码完成此操作时,最小的未划线号码就是我们的答案。
  5. 但是,它的空间要求很高。有没有更好更快的方法呢?

3 个答案:

答案 0 :(得分:3)

这是一个O(sort(K)) - 时间算法。

设1≤x 1 ≤x 2 ≤...≤x m 缺少的整数集合。对于从0到m的所有i,让y i = x 1 + x 2 + ... + x i 是第一个i项的部分和。如果存在,则令j为最小索引,使得y j + 1&lt; X <子> J + 1 ;否则,让j = m。可以通过归纳显示不能做出的最小和是y j + 1(假设是,对于从0到j的所有i,数字x 1 ,x 2 ,...,x i 可以使所有的总和从0到y i 而没有其他的总和。

为了处理指定缺失数字的事实,有一个优化可以在恒定时间内处理多个连续数字。我将它留作练习。

答案 1 :(得分:0)

设X为初始化为零的位向量。对于每个数字Ni,设置X =(X | X <&lt;&lt; Ni)|你。 (即你可以制作Ni,你可以增加你以前可以通过Ni制作的任何价值。)

这将为您可以制作的每个值设置一个“1”。

N的运行时间是线性的,并且bitvector操作很快。

process 1: X = 00000001
process 2: X = (00000001 | 00000001 << 2) | (00000010) = 00000111
process 4: X = (00000111 | 00000111 << 4) | (00001000) = 01111111

你不能做的第一个号码是8.

答案 2 :(得分:0)

这是我的O(K lg K)方法。由于懒惰溢出,我没有对它进行过多测试,对不起。如果它适合你,我可以解释这个想法:

const int MAXK = 100003;

int n, k;
int a[MAXK];

long long sum(long long a, long long b) { // sum of elements from a to b
  return max(0ll, b * (b + 1) / 2 - a * (a - 1) / 2);
}

void answer(long long ans) {
  cout << ans << endl;
  exit(0);
}

int main() 
{
    cin >> n >> k;
  for (int i = 1; i <= k; ++i) {
    cin >> a[i];
  }

  a[0] = 0;
  a[k+1] = n+1;

  sort(a, a+k+2);

  long long ans = 0;
  for (int i = 1; i <= k+1; ++i) {
    // interval of existing numbers [lo, hi]
    int lo = a[i-1] + 1;
    int hi = a[i] - 1;

    if (lo <= hi && lo > ans + 1)
      break;

    ans += sum(lo, hi);
  }

  answer(ans + 1);
}

编辑:好的,感谢上帝@DavidEisenstat在他的回答中写下了我使用的方法的描述,所以我不必写它。基本上,他提到的练习并不是一个接一个地添加“现有数字”,而是同时进行。在此之前,您只需要检查其中一些是否打破了不变量,这可以使用二进制搜索来完成。希望它有所帮助。

EDIT2 :正如@DavidEisenstat在评论中指出的那样,不需要二进制搜索,因为只有现有数字的每个区间中的第一个数字才能打破不变量。相应地修改了代码。