题意:我们要找到长度为 n 数组 A 的所有的长度为 m 的切片 si 最小的 mex(si) 值。
思路:
可以发现,如果记录切片中每一个数字出现的次数,找到第一个出现次数为0的就是答案。
但是我们不能每次切片改变都去遍历一次,这样会TLE,因此可以用一个数组M维护区间(i,i+m)数字出现的次数。
切片的末尾指向了 Ai 的时候,那么对应的
M
a
[
i
]
M_{a[i]}
Ma[i]就会加1;而
M
a
[
i
−
m
]
M_{a[i-m]}
Ma[i−m] 就会减1。
接下来分情况讨论优化算法效率
1.如果
M
a
[
i
−
m
]
M_{a[i-m]}
Ma[i−m]==0,且
a
i
−
m
a_{i-m}
ai−m<mex,那么可以肯定当前切片的mex值必然为
a
i
−
m
a_{i-m}
ai−m。
2.如果(1)情况没有发生,且
M
m
e
x
M_{mex}
Mmex!=0,说明当前切片答案必然不是mex,且大于mex,需向后寻找。
3.如果(1)(2)都不发生,那么mex不变。
code:
#include <bits/stdc++.h>
using namespace std;
#define mos 1500010
#define ll long long
ll n,m;
ll a[mos];
ll flag[mos];
int main()
{
cin>>n>>m;
ll ans=1e18;
for (ll i=0;i<n;i++)
cin>>a[i];
for (ll i=0;i<m;i++)
flag[a[i]]++;//对第一组切片初始化
ll mex=0;
for (ll i=0;;i++)//找到第一组切片的mex值
{
if (flag[i]==0)
{ mex=i;
break;
}
}
ans=min(ans,mex);//这步不能少,不然漏情况
for (ll i=m;i<n;i++)
{
flag[a[i-m]]--;//首元素出队,出现次数--
flag[a[i]]++;//尾元素出队,出现次数++
if (flag[a[i-m]]==0 && a[i-m]<mex)//情况1
{
mex=a[i-m];
}
else if (flag[mex]!=0)//情况2
{
while (flag[mex]!=0)
{
mex++;
}
}
ans=min(ans,mex);
}
cout<<ans<<endl;
//system("pause");
return 0;
}