您的位置:首页 > 编程语言 > Go语言

【USACO 2013 January Gold】奶牛排队

2013-12-18 14:46 519 查看
Description
农夫约翰的N(1 <= N <= 100,000)只奶牛排成了一队,每只牛都用编上了一个“血统编号”,该编号为范围0...1,000,000,000的整数。血统相同的奶牛有相同的编号,也就是可能有多头奶牛是相同的"血统编号"。 

约翰觉得如果连续排列的一段奶牛有相同的血统编号的话,奶牛们看起来会更具有威猛。为了创造这样的连续段,约翰最多能选出k种血统的奶牛,并把他们全部从队列中赶走。请帮助约翰计算这样做能得到的由相同血统编号的牛构成的连续段的长度最大是多少?
Input
第一行,两个空格间隔的整数N和K 

接下来N行, 每行一个整数,表示对应奶牛的血统编号
Output
一行,一个整数,表示所能得到的最大连续段的长度
Sample Input

9 1
2
7
3
7
7
3
7
5
7


Sample Output

4


Hint
样例说明,只能删除一种奶牛,删除3号血统的奶牛可得到2777757,其中最长的一段连续数字是4个7

【分析】

        原题目其实可以等价为:选择一段区间[i,j],使得区间内至少有k+1中颜色,定义Ai表示这一段区间最多的一种颜色的个数。那么答案显然就是max{Ai}了。

        枚举区间左右端点肯定是不行的,我们只需要枚举左端点,而右端点可以继承上一个右端点的位置,然后往后延展至满足条件的最远处。而取区间内颜色最多的一种,我们只需要用一个堆或者优先队列来动态维护即可。

【代码】

/*******************
ID:Ciocio
LANG:C++
DATE:2013-12-16
TASK:USACO-2013-Jan-Gold
*******************/
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <queue>
#include <utility>
#include <functional>
#include <vector>
#include <map>

using namespace std;

#define MAXN 100005
#define m_p make_pair

typedef pair<int,int> pii;
struct node{
int v,bh;
bool operator<(const node &A)const{
return v<A.v;}
}P[MAXN];
int N,K;
int v[MAXN],cnt[MAXN];

template <class T>
void _read(T &x)
{
char tt=getchar();
while(tt<'0'||'9'<tt) tt=getchar();
for(x=0;'0'<=tt&&tt<='9';x=x*10+tt-'0',tt=getchar());
}

void _init()
{
_read(N);_read(K);
for(int i=1;i<=N;i++) _read(P[i].v),P[i].bh=i;
sort(P+1,P+N+1);
int bh=0;
P[0].v=-1;v[0]=-1;
for(int i=1;i<=N;i++) //离散化重编号,为了使颜色可为数组下标
{
if(P[i].v!=P[i-1].v) bh++;
v[P[i].bh]=bh;
}
}

priority_queue<pii,vector<pii>,less<pii> >PQ; //优先队列,less表示大数优先
void _solve()
{
while(!PQ.empty()) PQ.pop();
int now,ans;
now=ans=cnt[v[1]]=1;
PQ.push(m_p(cnt[v[1]],v[1]));
for(int i=1,j=1;i<=N&&j<=N;) //[i,j]这段区间
{
while(j<N&&now<K+1) //j继承并向后延展
{
j++;
if(!cnt[v[j]]) now++;
cnt[v[j]]++;
PQ.push(m_p(cnt[v[j]],v[j]));
}
while(now==K+1&&j<N&&cnt[v[j+1]]!=0) //处理颜色已满,但可继续延展的情况
{
j++;
cnt[v[j]]++;
PQ.push(m_p(cnt[v[j]],v[j]));
}
while((!PQ.empty())&&(PQ.top().first!=cnt[PQ.top().second])) //从优先队列中去除不符条件的
PQ.pop();
if(!PQ.empty()) //更新答案
ans=max(ans,PQ.top().first);
cnt[v[i]]--; //左端点向后移一位
if(cnt[v[i]]==0) now--;
PQ.push(m_p(cnt[v[i]],v[i]));
i++;
}
cout<<ans<<endl;
}

int main()
{
_init();
_solve();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: