给出从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筛子的东西,用于寻找素数。同样的想法,但为不同的目的有不同的规则。
但是,它的空间要求很高。有没有更好更快的方法呢?
答案 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在评论中指出的那样,不需要二进制搜索,因为只有现有数字的每个区间中的第一个数字才能打破不变量。相应地修改了代码。