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
Output
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;
}