题目链接:[POI2005]SAM-Toy Cars - 洛谷
真是太感谢写翻译的人了!(๑•̀ㅂ•́)و✧
先说思路:
思路:贪心+堆优化
注意:堆最好手写,不要用stl。(不要问我为什么,我可吃过大亏的!)
不难得出,每次空间不足要放回去的,就是下一次使用离现在时间最长的。
问题就来了:咋求“下一次使用离现在时间最长的”?
1.可以用一次循环比遍历,时间代价,由于过不了,我就没写。
2.使用vector存储,每次二分找出插入位置,最后一项就是“下一次使用离现在时间最长的”,虽然复杂度够,但是常数太大,还是TLE。
3.用堆优化,大根堆,每次的“下一次使用离现在时间最长的”就是根,插入时简单处理一下就ok了。
代码:
//题目:https://www.luogu.com.cn/problem/P3419
//日期:2023年5月3日
#include<bits/stdc++.h>
#define N 100000
#define P 500000
using namespace std;
vector<int>dis[2*N];
int a[2*P]={},d[2*N]={},w[2*N]={},ans=0,cnt=0,k=0,n=0,p=0;
bool flg[2*N]={};
inline void push_right(int node);
inline void push_right2(int node);
int main(){
scanf("%d%d%d",&n,&k,&p);
for(int i=1;i<=p;i++){
scanf("%d",&a[i]);
dis[a[i]].push_back(i);
}
for(int i=1;i<=n;i++){
dis[i].push_back(1<<30);
}
for(int i=1;i<=p;i++){
if(flg[a[i]]==false){
dis[a[i]].erase(dis[a[i]].begin());
if(cnt<k){
cnt++;
flg[a[i]]=true;
d[cnt]=a[i];
w[a[i]]=cnt;
push_right(cnt);
ans++;
}
else{
swap(w[d[1]],w[a[i]]);
flg[a[i]]=true;
flg[d[1]]=false;
d[1]=a[i];
push_right2(1);
ans++;
}
}
else{
dis[a[i]].erase(dis[a[i]].begin());
if(dis[d[w[a[i]]]][0]>dis[d[w[a[i]]/2]][0]){
push_right(w[a[i]]);
}
else{
push_right2(w[a[i]]);
}
}
}
printf("%d\n",ans);
return 0;
}
inline void push_right(int node){
int fa=node/2,sn=node;
while(sn>1){
if(dis[d[sn]][0]<dis[d[fa]][0]){
return;
}
else{
swap(w[d[sn]],w[d[fa]]);
swap(d[sn],d[fa]);
sn=fa;
fa=sn/2;
if(sn==1){
return;
}
}
}
return;
}
inline void push_right2(int node){
int fa=node,sn=node*2;
while(sn<=cnt){
if(sn+1<=cnt&&dis[d[sn+1]][0]>dis[d[sn]][0]){
sn++;
}
if(dis[d[fa]][0]>dis[d[sn]][0]){
return;
}
else{
swap(w[d[fa]],w[d[sn]]);
swap(d[fa],d[sn]);
fa=sn;
sn=fa*2;
if(sn>=cnt){
return;
}
}
}
}
就这样?......