【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
Sample Output
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;
}
农夫约翰的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;
}
相关文章推荐
- 【usaco-Liars and Truth Tellers, 2013 Jan真假奶牛】并查集
- [usaco]2013-jan Liars and Truth Tellers 真假奶牛
- 奶牛排队(USACO)( JSOI夏令营2017 day1 T2 ) * * *【O(nlogn)最长上升子序列】
- 【USACO 2013 January Gold】座位 --线段树
- P2052【USACO 2013 January Gold】座位
- 【usaco2013 mar】懒惰的奶牛[b](lazy_bronze.pas/cpp/c) //2018.1.28
- 【题】【线段树】NKOJ 2052 【USACO 2013 January Gold】座位
- BSOJ 4208 -- 【USACO 2013 Jan】奶牛队列
- USACO 奶牛排队
- 【USACO 2013 March Gold】奶牛逃跑
- 【usaco2013 mar】奶牛的声音(mooomoo.pas/cpp/c)//2018.1.28
- [USACO2013 Jan]Liars and Truth Tellers真假奶牛
- 【USACO】2013 Jan Liars and Truth Tellers 真假奶牛
- bzoj 1667: [Usaco2006 Oct]Cows on Skates滑旱冰的奶牛(BFS)
- BZOJ3126: [Usaco2013 Open]Photo
- [Usaco2013 Jan] Square Overlap
- 【BZOJ】1703: [Usaco2007 Mar]Ranking the Cows 奶牛排名
- bzoj1648: [Usaco2006 Dec]Cow Picnic 奶牛野餐
- NOIP2013火柴排队[逆序对]
- 洛谷P2915 [USACO08NOV]奶牛混合起来Mixed Up Cows