(CodeForces) L - LRU Algorithm Gym - 102394L (模拟+字典树)

本文介绍了一种使用字典树和模拟LRU缓存策略解决特定序列匹配问题的方法。通过构建字典树存储查询序列,并利用STL进行高效操作,实现了在未知物理块数量的情况下,判断查询序列是否曾出现在操作序列中。文章详细阐述了解决方案的实现过程,包括字典树的构建、LRU缓存模拟以及查询匹配。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

传送门

题意:给定一个n个数的数字序列,第i个数为a[i],每次操作会将a[i]插入或移到最前端:

1.若a[i]已经在序列中出现过,则将其移到最前端,并删除原出现位置

2.若a[i]未出现过,则直接将其插入到最前端

有q个询问,每个询问给出一个长度为m的序列,问是否在某个时刻询问序列与操作的序列相同,忽略后缀的0

(就是操作系统中的LRU,刚好在学

解:由于物理块的个数不知道,我们可以忽略最近最久未使用的删除操作,只执行上述将其移动到最前面的操作;在模拟之前我们将q次查询的序列插入字典树,这里的字典树用unordered_map来操作就好了,记录每个序列的结束节点;然后我们就模拟lru,每一次循环,就在字典树中跑一次当前的list,跑到的点就vis为1,这样我们最后只要看结束节点就可以了(用stl是很方便,不过被卡了就很难受了。

#include<bits/stdc++.h>
#define il inline
#define pb push_back
#define ms(_data,v) memset(_data,v,sizeof(_data))
#define SZ(a) int((a).size())
using namespace std;
typedef long long ll;
const ll inf=0x3f3f3f3f;
const int N=2e6+5;
template <typename _Tp> il void read(_Tp&x) {
	char ch;bool flag=0;x=0;
	while(ch=getchar(),!isdigit(ch)) if(ch=='-')flag=1;
	while(isdigit(ch)) x=x*10+ch-'0',ch=getchar();
	if(flag) x=-x;
}
//il int Add(int &x,ll y) {return x=x+y>=mod?x+y-mod:x+y;}
//il int Mul(int &x,ll y) {return x=x*y>=mod?x*y%mod:x*y;}
int T,n,q,a[N],len[N],b[N];
unordered_map<int,int> tr[N];
int cnt,root;
bool vis[N];
int newnode(){
    ++cnt;
    tr[cnt].clear(),vis[cnt]=0;
    return cnt;
}
void init(){
    cnt=0;
    root=newnode();
}
int add(int len){
    int rt=root;
    for(int i=1;i<=len;++i){
        if(!tr[rt].count(b[i])){
            tr[rt][b[i]]=newnode();
        }
        rt=tr[rt][b[i]];
    }
    return rt;//结点坐标
}
int ls[N];
list<int>::iterator mp[N];
list<int> li;
void run(){
    li.clear();
    for(int i=1;i<=n;++i) mp[a[i]]=li.end();
    for(int i=1;i<=n;++i){
        if(mp[a[i]]!=li.end()){
            li.erase(mp[a[i]]);
        }
        li.push_front(a[i]);
        mp[a[i]]=li.begin();

        int rt=1;
        for(auto u:li){
            if(!tr[rt].count(u)){
                break;
            }
            rt=tr[rt][u];
            vis[rt]=1;
        }
        while(tr[rt].count(0)){
            rt=tr[rt][0];
            vis[rt]=1;
        }
    }
    //检查所有查询串的结束节点
    for(int i=1;i<=q;++i){
        if(vis[ls[i]]) printf("Yes\n");
        else printf("No\n");
    }

}
int main(){
//    std::ios::sync_with_stdio(0);cin.tie(0);
    read(T);
    while(T--){
        init();
        read(n),read(q);
        for(int i=1;i<=n;++i) read(a[i]);
        for(int i=1;i<=q;++i){
            read(len[i]);
            for(int j=1;j<=len[i];++j) read(b[j]);
            ls[i]=add(len[i]);
        }
        run();
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值