【题解】AT_abc290_c 题解
AT_abc290_c 题解
思路分析
一道挺不错的思维题。
首先我们要证明两个结论:
- 对于长度为 的数组 , 不超过 。
- 答案为 到 中最小的在数组中未出现的数。如果不存在,就为 。
对于第一个结论,设 。由于 到 都要在 中出现,共 个数。所以 应当不超过 ,证毕。
对于第二个结论,令答案为 。答案要求 到 均在数组中。如果不在,就一定不连续。我们为了连续,就要从数组分离出一段连续的 到 。而由于枚举的是 到 ,如果有数不存在数组中,说明不连续,否则能一一对应。所以,找到了最小的未出现的数 ,就说明前面的 到 一定存在,否则不是最小。而如果 到 都不是,则 到 都存在于数组中。又由结论一,只能为 ,证毕。
最后,按照结论二给出的方式实现即可。由于只需要判断存在性,与某个数的个数无关,所以可以使用 STL 函数 unique 去重优化时间复杂度。又由于需要判断一个较长的数组中某个数的存在性,而数组单个数可能很大,无法用桶。所以可以排序去重后使用二分搜索来判断。
代码
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 3e5 + 10;
int a[N];
bool findex(int nx, int num) //findex(nx, num) 指在去重后长度为 nx 的数组中判断 num 是否存在。
{
int l = 1, r = nx; //左右指针分别数组的首尾。
while(l <= r)
{
int mid = (l + r) >> 1; //取中间。
if(a[mid] == num) //找到了。
{
return true;
}
else if(a[mid] > num) //如果比待找数大,
{
r = mid - 1; //缩小范围,范围移到左半部分。
}
else //否则比待找数小,
{
l = mid + 1; //缩小范围,范围移到右半部分。
}
}
return false;
}
int main()
{
int n, k;
cin >> n >> k;
for(int i = 1;i <= n;i++) cin >> a[i];
sort(a + 1, a + n + 1); //unique 去重前要排序。
int len = unique(a + 1, a + n + 1) - a; //unique 返回的是尾指针,需要减去头指针计算长度。
for(int i = 0;i < k;i++) //枚举 0 到 k - 1
{
if(!findex(len, i)) //如果不存在,
{
cout << i << endl; //就输出并结束程序,即可保证最小。
return 0;
}
}
cout << k << endl; //如果都存在,输出 k。
return 0;
}

浙公网安备 33010602011771号