稍微观察即可发现,若当前高速缓存已满,对于两个数a,b,
删去a更优仅当下一个a 比下一个b先出现,
那么倒序扫一边,求出下一个ai出现得位置。
然后正向扫一遍,对于每次求出下一个出现位置最靠后得点,然后删去这个点即可...
我用得线段树维护,可能有点麻烦?
c++代码如下:
#include<bits/stdc++.h>
#define rep(i,x,y) for(register int i = x ; i <= y ; ++ i)
#define repd(i,x,y) for(register int i = x ; i >= y ; -- i)
using namespace std;
typedef long long ll;
template<typename T>inline void read(T&x)
{
x = 0;char c;int sign = 1;
do { c = getchar(); if(c == '-') sign = -1; }while(!isdigit(c));
do { x = x * 10 + c - '0'; c = getchar(); }while(isdigit(c));
x *= sign;
}
const int N = 1e5+500,inf = 1e9+7,P = 1e9;
map<int,int>mp;
int a[N],nxt[N],root,ans,n,m;
int sz,ls[2000000],rs[2000000];
struct Str
{
int p,x,t;
bool operator < (const Str b)const { return x < b.x; };
}val[2000000];
bool find(int id,int l,int r,int p)
{
if(!id) return false;
if(l == r) return val[id].t;
int mid = l + r>> 1;
if(p <= mid) return find(ls[id],l,mid,p);
else return find(rs[id],mid + 1,r,p);
}
void modify(int id,int l,int r,int p)
{
if(l == r) { val[id].t--;if(!val[id].t) val[id].x = 0; return; }
int mid = l + r >> 1;
if(p <= mid) modify(ls[id],l,mid,p);
else modify(rs[id],mid + 1,r,p);
val[id] = max(val[ls[id]],val[rs[id]]);
}
void update(int&id,int l,int r,int p,int x,bool k)
{
if(!id) id = ++sz,val[id].p = l;
if(l == r) { val[id].x = x;val[id].t += k; return; }
int mid = l + r >> 1;
if(p <= mid) update(ls[id],l,mid,p,x,k);
else update(rs[id],mid + 1,r,p,x,k);
val[id] = max(val[ls[id]],val[rs[id]]);
}
int main()
{
read(n); read(m);
rep(i,1,n) read(a[i]);
repd(i,n,1)
{
if(!mp[a[i]]) nxt[i] = n + 1;
else nxt[i] = mp[a[i]];
mp[a[i]] = i;
}
rep(i,1,n)
{
if(find(root,1,P,a[i])) { update(root,1,P,a[i],nxt[i],0); continue; }
if(ans >= m) modify(root,1,P,val[root].p);
ans++; update(root,1,P,a[i],nxt[i],1);
}
cout << ans << endl;
return 0;
}