AtCoder - abc194_e Mex Min

题目:AtCoder - abc194_e

题意:我们要找到长度为 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[im] 就会减1。

接下来分情况讨论优化算法效率
1.如果 M a [ i − m ] M_{a[i-m]} Ma[im]==0,且 a i − m a_{i-m} aim a i − m a_{i-m} aim
2.如果(1)情况没有发生,且 M m e x M_{mex} Mmex!=0,说明当前切片答案必然不是mex,且大于mex,需向后寻找。
3.如果(1)(2)都不发生,那么mex不变。

code:

#include 
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;
}

你可能感兴趣的:(AtCoder - abc194_e Mex Min)