【BZOJ3048】Cow lineup,贪心+队列维护(或二分答案)

传送门(权限题)
题面:
3048: [Usaco2013 Jan]Cow Lineup

Time Limit: 2 Sec Memory Limit: 128 MB
Submit: 121 Solved: 89
[Submit][Status][Discuss]
Description

Farmer John’s N cows (1 <= N <= 100,000) are lined up in a row. Each cow is identified by an integer “breed ID” in the range 0…1,000,000,000; the breed ID of the ith cow in the lineup is B(i). Multiple cows can share the same breed ID. FJ thinks that his line of cows will look much more impressive if there is a large contiguous block of cows that all have the same breed ID. In order to create such a block, FJ chooses up to K breed IDs and removes from his lineup all the cows having those IDs. Please help FJ figure out the length of the largest consecutive block of cows with the same breed ID that he can create by doing this.

给你一个长度为n(1<=n<=100,000)的自然数数列,其中每一个数都小于等于10亿,现在给你一个k,表示你最多可以删去k类数。数列中相同的数字被称为一类数。设该数列中满足所有的数字相等的连续子序列被叫做完美序列,你的任务就是通过删数使得该数列中的最长完美序列尽量长。
Input

  • Line 1: Two space-separated integers: N and K.
  • Lines 2..1+N: Line i+1 contains the breed ID B(i).

Output

  • Line 1: The largest size of a contiguous block of cows with identical breed IDs that FJ can create.

Sample Input

9 1

2

7

3

7

7

3

7

5

7

INPUT DETAILS: There are 9 cows in the lineup, with breed IDs 2, 7, 3, 7, 7, 3, 7, 5, 7. FJ would like to remove up to 1 breed ID from this lineup.

Sample Output

4

OUTPUT DETAILS: By removing all cows with breed ID 3, the lineup reduces to 2, 7, 7, 7, 7, 5, 7. In this new lineup, there is a contiguous block of 4 cows with the same breed ID (7).

HINT

样例解释:

长度为9的数列,最多只能删去1类数。

不删,最长完美序列长度为2.

删去一类数3,序列变成2 7 7 7 7 5 7,最长完美序列长度为4.因此答案为4

写在前面:诸事不顺
思路:昨天测试题,第一眼觉得是DP,还要用”树“据结构维护一下?感觉复杂度不可能是 O(n) ,更不可能是 O(n2) ,然后就去先写下面的题目了。测试完晓得先离散化,然后二分答案和队列维护,复杂度也挺科学的,但我发现对于快速得到当前队列中各数出现的次数的最大值是件难事,想着用树状数组和线段树好像都不简单,“难道n^2枚举?时间就爆了啊”,无奈放弃,后来看到有贪心的做法,就是队列中≤k种时就一直放数,等于k+1种时就看看下一个数有没有在队列中出现过,出现过就扔进来,没有就中止当前循环,最后head++。但记录最大值仍然是个问题,总之昨晚一直没有想出来,后来看到Yveh的blog才发现自己煞笔了,因为我们要求的是只是最多删去k种后的最大连续长度,队列中各数出现次数的最大值只是一个辅助,每次ans去和最大值比较就可以变成ans去和可能出现的最大值比较,也就是说当有数的出现次数增加时才有必要去和ans比较,而数的次数减少并不会影响最终的答案
注意:离散化可以用set,也可以排序后重新赋值,都是 O(nlogn) ,但好像排序的常数小一些?
代码:

#include<bits/stdc++.h>
#include<set>
using namespace std;
int l,r,ans,n,k,tot;
map<int,int>mp;
int flag[100010],a[100010];
int q[100010];
main()
{
    scanf("%d%d",&n,&k);
    for (int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        if (!mp[a[i]]) mp[a[i]]=++tot;
        a[i]=mp[a[i]];
    }
    l=1;r=0;
    int kind=0,i=0;
    while (i<n)
    {
        while (i<n&&kind<=k)
        {
            q[++r]=a[++i];
            if (!flag[a[i]]) kind++;
            flag[a[i]]++;
            ans=max(ans,flag[a[i]]);
        }
        while (kind==k+1&&i<n)
        {
            if (!flag[a[i+1]]) break;
            q[++r]=a[++i];
            flag[a[i]]++;
            ans=max(ans,flag[a[i]]);
        }
        if (flag[q[l]]==1) kind--;
        flag[q[l]]--;
        l++;
    }
    printf("%d",ans);
}

Beiyu的二分+树状数组
树状数组维护感觉好厉害,前排膜拜QAQ

你可能感兴趣的:(【BZOJ3048】Cow lineup,贪心+队列维护(或二分答案))