传送门
题目解析:
~~~~~~~
其实题意很简单,就是模拟一个LRU算法,很显然的知道cache的值要二分,重要的是怎么样去写这个check函数,check的核心就是去维护一个排位序列,支持插入和删除,修改就是插入和删除的组合,这里为了使check函数的复杂度能达到O(n),我们用数组模拟双链表,并且用unordered_map存储位置,达到O(1)的插入和删除,模拟双链表的过程当中其实并不需要刻意的记录双链表中插入元素的头和尾,我们可以设置两个哨兵,一个放在最前面,一个放在最后面,固定位置,通过指针同样可以快速的找出已插入元素的头和尾
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<unordered_map>
using namespace std;
const int N=2e5+10;
int a[N];
int lis[N],top,en;
int up[N],down[N];
int n,k;
bool check(int mid)
{
unordered_map<int,int> mp;
for(int i=0;i<N;i++)
{
lis[i]=up[i]=down[i]=0;
}
top=1,en=1;
lis[1]=a[1];
mp[a[1]]=1;
up[1]=0,down[1]=n+1;
down[0]=1,up[n+1]=1;
int ans=0,mps=1;
for(int i=2;i<=n;i++)
{
if(mp[a[i]])
{
int pos=mp[a[i]];
lis[pos]=0;
up[down[pos]]=up[pos];
down[up[pos]]=down[pos];
lis[++en]=a[i];
mp[a[i]]=en;
int tt=up[n+1];
up[en]=tt,down[en]=n+1;
down[tt]=en,up[n+1]=en;
ans++;
}
else if(mps<mid)
{
lis[++en]=a[i];
mp[a[i]]=en;
int tt=up[n+1];
up[en]=tt,down[en]=n+1;
down[tt]=en,up[n+1]=en;
mps++;
}
else
{
int pos=down[0];
mp[lis[pos]]=0;
lis[pos]=0;
up[down[pos]]=up[pos];
down[up[pos]]=down[pos];
lis[++en]=a[i];
int tt=up[n+1];
up[en]=tt,down[en]=n+1;
down[tt]=en,up[n+1]=en;
mp[a[i]]=en;
}
}
return ans>=k;
}
int main()
{
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)cin>>a[i];
int l=1,r=n+1;
while(l<r)
{
int mid=l+r>>1;
if(check(mid))r=mid;
else l=mid+1;
}
if(r==n+1)puts("cbddl");
else cout<<r<<endl;
return 0;
}