BZOJ_P3048 [Usaco2013 Jan]Cow Lineup(二分答案+树状数组/单调队列)

12 篇文章 0 订阅
10 篇文章 0 订阅

BZOJ传送门

Time Limit: 2 Sec Memory Limit: 128 MB
Submit: 113 Solved: 82
[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.

Source

Gold

Sol:
先二分答案,然后计算形成连续mid个数至少需要删掉多少个数,如果小于等于k那么直接返回就行了。
用树状数组维护区间内不同的数的个数(别忘-1,减去这个数的贡献),然后随便搞搞就可以了。
时间复杂度O(n log^2 n)
ps:某B姓OJ垫底2333 差400ms超时23333

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<vector>
#include<iostream>
using namespace std;
#define N 100005
inline int in(int x=0,char ch=getchar(),int v=1){
    while(ch!='-'&&(ch>'9'||ch<'0')) ch=getchar();if(ch=='-') v=-1,ch=getchar();
    while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();return x*v;
}
int n,k,l,r,mid,cnt,t;
int a[N],s[N],lst[N],d[N],w[N];
map<int,int> mp;vector<int> g[N];
inline void Add(int x,int v){for(;x<=n;x+=x&-x){if(w[x]!=t) d[x]=0,w[x]=t;d[x]+=v;}}
inline int Sum(int x,int res=0){for(;x;x-=x&-x) if(w[x]==t) res+=d[x];return res;}
inline int find(int x,int v){
    int l=0,r=s[x]-1,mid;
    while(l<r){
        mid=(l+r)>>1;
        if(g[x][mid]>v) r=mid-1;else if(g[x][mid]<v) l=mid+1;else return mid;
    }return l;
}
inline int calc(int p){
    ++t;memset(lst,0,sizeof(lst));int tmp=0;
    for(int i=1,v;i<=n;i++){
        if(!lst[a[i]]) Add(i,1),lst[a[i]]=i;
        else Add(lst[a[i]],-1),Add(i,1),lst[a[i]]=i;
        if(s[a[i]]>=p)
            if((v=find(a[i],i))+1>=p){
                tmp=Sum(i)-Sum(g[a[i]][v-p+1]-1)-1;
                if(tmp<=k) return 1;}
    }
    return 0;
}
int main(){
    n=in(),k=in();int x;mp.clear();
    for(int i=1;i<=n;i++){
        if(x=in(),mp.count(x)) x=mp[x];else mp[x]=++cnt,x=cnt;
        a[i]=x;g[x].push_back(i);
    }
    for(int i=1;i<=cnt;i++) s[i]=g[i].size();
    l=0,r=n;
    while(l+1<r){mid=(l+r)>>1;if(!calc(mid)) r=mid-1;else l=mid;}
    if(calc(l+1)) printf("%d\n",l+1);
    else printf("%d\n",l);
    return 0;
}

官方题解
This problem is equivalent to finding, out of all contiguous subintervals containing at most K+1 distinct breed IDs, the maximal number of cows of a single breed contained within such an interval.

The idea is to sweep down the array of cows, keep tracking of the left and right endpoints of an interval. Each time we increment the right endpoint, we may need to increment the left endpoint by some amount so that the interval contains at most K+1 distinct IDs. Of course, when we do this, we will increment the left endpoint as little as possible. To do this, we just need to keep track of (i) for each breed ID, how many cows of that ID are in the interval and (ii) how many distinct breed IDs have a nonzero number of cows in the interval.

Now, when examining any interval, we need to know the maximal number of cows of a single breed in that interval. One approach is to use a data structure such as a set or priority queue to maintain the maximum. Since at most K+1 IDs are nonzero at any given time, this solution takes O(N log(K)) time.

An even simpler approach involves the observation that during this sweep process, at some point the left endpoint will actually be pointing to the correct breed ID, and at this time the interval will contain as many cows of that ID as possible. In other words, rather than asking “Given an interval, what is the maximal number of cows of a single ID within this interval?”, we ask “Given a cow, what is the maximum number of cows of that ID which can be in an interval with that cow as the left endpoint?” This solution takes O(N) time.
官方代码

#include <iostream>
#include <cstdio>
#include <map>
#include <set>

using namespace std;

int A[100010];

int main() {
  freopen("lineup.in", "r", stdin);
  freopen("lineup.out", "w", stdout);

  int N, K; cin >> N >> K;
  for(int i = 0; i < N; i++) {
    cin >> A[i];
  }

  int res = 0;
  int nz_cnt = 0;
  map<int, int> cnt;
  for(int i = 0, j = 0; i < N; i++) {
    int& ci = cnt[A[i]];
    if(ci == 0) nz_cnt++;
    ci++;

    for(; nz_cnt > K + 1; j++) {
      int& cj = cnt[A[j]];
      --cj;
      if(cj == 0) nz_cnt--;
    }

    res = max(res, ci);
  }
  cout << res << endl;

  return 0;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值