• acd


    题意:一个由n个数组成的序列(序列元素的范围是[0, n])。求最长前缀 j 。使得在这个前缀 j 中对于随意的数 i1 < i2。都满足随意的 m <= j。i1 在前 m 个数里出现的次数 >= i2 在前 m 个数里出现的次数 - k (1 ≤ n ≤ 200 000, 0 ≤ k ≤ 200 000)。

    题目链接:http://acdream.info/problem?pid=1427

    ——>>第一个前缀 j 不满足。那么后面的前缀一定不满足(由于前缀 j 不满足)。

    所以,从左往右扫描,每次取全部数字 i 的最少出现次数与当前扫描到的数出现的次数比較看是否满足条件就可以。

          全部数字 i 指的是哪些数字呢?是已经出现过的数吗?例子2说明不是。。是不大于当前出现过的最大整数吗?WA告诉我不是。

    。而是 <= a[j] 的全部非负整数。

          全部数字 i 出现次数的最小值。我想到了RMQ和线段树,最后选了线段树来维护这个最小值。

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    
    #define lc (o << 1)
    #define rc ((o << 1) | 1)
    
    using std::min;
    using std::max;
    
    const int MAXN = 200000 + 10;
    const int INF = 0x3f3f3f3f;
    
    int n, k, Max;
    int minv[MAXN << 2], cnt[MAXN];
    int a[MAXN];
    
    void Read()
    {
        Max = -1;
        for (int i = 1; i <= n; ++i)
        {
            scanf("%d", a + i);
            ++a[i];
            if (a[i] > Max)
            {
                Max = a[i];
            }
        }
    }
    
    void Build(int o, int L, int R)
    {
        minv[o] = 0;
        if (L == R) return;
        int M = (L + R) >> 1;
        Build(lc, L, M);
        Build(rc, M + 1, R);
    }
    
    void Update(int o, int L, int R, int q)
    {
        if (L == R)
        {
            minv[o] = cnt[q];
            return;
        }
        int M = (L + R) >> 1;
        if (q <= M) Update(lc, L, M, q);
        else Update(rc, M + 1, R, q);
        minv[o] = min(minv[lc], minv[rc]);
    }
    
    int Query(int o, int L, int R, int ql, int qr)
    {
        if (ql <= L && R <= qr)
        {
            return minv[o];
        }
        int ret = INF;
        int M = (L + R) >> 1;
        if (ql <= M) ret = min(ret, Query(lc, L, M, ql, qr));
        if (qr > M) ret= min(ret, Query(rc, M + 1, R, ql, qr));
    
        return ret;
    }
    
    void Solve()
    {
        int i;
    
        memset(cnt, 0, sizeof(cnt));
        for (i = 1; i <= n; ++i)
        {
            ++cnt[a[i]];
            Update(1, 1, Max, a[i]);
            if (Query(1, 1, Max, 1, a[i]) < cnt[a[i]] - k) break;
        }
        printf("%d
    ", i - 1);
    }
    
    int main()
    {
        while (scanf("%d%d", &n, &k) == 2)
        {
            Read();
            Build(1, 1, Max);
            Solve();
        }
    
        return 0;
    }
    


  • 相关阅读:
    UVa 1349 (二分图最小权完美匹配) Optimal Bus Route Design
    UVa 1658 (拆点法 最小费用流) Admiral
    UVa 11082 (网络流建模) Matrix Decompressing
    UVa 753 (二分图最大匹配) A Plug for UNIX
    UVa 1451 (数形结合 单调栈) Average
    UVa 1471 (LIS变形) Defense Lines
    UVa 11572 (滑动窗口) Unique Snowflakes
    UVa 1606 (极角排序) Amphiphilic Carbon Molecules
    UVa 11054 Wine trading in Gergovia
    UVa 140 (枚举排列) Bandwidth
  • 原文地址:https://www.cnblogs.com/jzssuanfa/p/6806149.html
Copyright © 2020-2023  润新知