2021 Jiangxi Provincial Collegiate Programming Contest J. LRU (二分答案,优先队列)
-
题意:有\(n\)个待完成的任务,每个任务都有编号,有一队列,如果队列没满,就将任务入队,否则,查询队列中是否有和当前任务编号相同的任务,如果有,将其提到队位,贡献+1,否则,排出队头。现在问你队列的容量最少为多少能满足贡献不小于\(k\).
-
题解:很明显,\(k\)具有单调性,我们可以二分答案。现在来看check函数,我们用优先队列按入队时间存任务,用map来存每个任务的入队时间,如果队列没满,直接入队,如果当前任务在队列中,直接更改map,这里不需要对队列进行操作,否则会TLE,我们可以在后面需要放新任务的时候来更新,这样的话复杂度就是线性的。
-
代码:
#include <bits/stdc++.h> #define ll long long #define fi first #define se second #define pb push_back #define me memset #define rep(a,b,c) for(int a=b;a<=c;++a) #define per(a,b,c) for(int a=b;a>=c;--a) const int N = 1e6 + 10; const int mod = 998244353; const int INF = 0x3f3f3f3f; using namespace std; typedef pair<int,int> PII; typedef pair<ll,ll> PLL; ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;} ll lcm(ll a,ll b) {return a/gcd(a,b)*b%mod;} int n,k; int a[N]; struct Node{ int idx,timestamp; bool operator < (const Node &mikoto) const{ return timestamp>mikoto.timestamp; }; }c; bool check(int x){ unordered_map<int,int> mp; priority_queue<Node> h; int res=0; for(int i=1;i<=n;++i){ if(mp[a[i]]){ //visted mp[a[i]]=i; res++; continue; } if((int)h.size()<x){ //not visted and not full mp[a[i]]=i; c={a[i],i}; h.push(c); continue; } while(h.top().timestamp != mp[h.top().idx]){ auto now=h.top(); h.pop(); now.timestamp=mp[now.idx]; h.push(now); } auto now=h.top(); h.pop(); mp[now.idx]=0; mp[a[i]]=i; c={a[i],i}; h.push(c); } return res>=k; } int main() { scanf("%d %d",&n,&k); for(int i=1;i<=n;++i){ scanf("%d",&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) printf("%d\n",r); else puts("cbddl"); return 0; }
𝓐𝓬𝓱𝓲𝓮𝓿𝓮𝓶𝓮𝓷𝓽 𝓹𝓻𝓸𝓿𝓲𝓭𝓮𝓼 𝓽𝓱𝓮 𝓸𝓷𝓵𝔂 𝓻𝓮𝓪𝓵
𝓹𝓵𝓮𝓪𝓼𝓾𝓻𝓮 𝓲𝓷 𝓵𝓲𝓯𝓮