2019哈尔滨CCPC L.LRU Algorithm(模拟+字典树)

给出一个LRU算法的操作序列,q个查询,询问在内存池大小为m时,LRU操作过程中会不会出现查询给出的内存池状态。

我们发现内存池大小的限制因为LRU算法的特殊性质,仅仅只是把当前状态限制成了无限内存池大小的一个前缀。

这题就变成了一个前缀匹配问题。由于n比较小,可以考虑n方的算法,模拟LRU算法的过程,不加内存限制,对于每一个中间状态,都去跑一遍查询建立的字典树,在字典树上经过的前缀显然就是答案Yes。

要不是打了多校我还真不太会模拟LRU,但是牛客多校出了一题模拟LRU,题解给出了一种迭代器数组记录list链表每一种数字迭代器位置,O(n)且快乐简短的做法(当时写了一个nlogn的也过了,不过贼恶心),再做这题就很愉快了,短短几行就写完了。

踩过的坑:
查询有1 2 3 0 0 0这种后缀带0的,代表着此时内存池没有满,有三个空位,这种时候仍然把0加入字典树,并且在跑出的LRU状态在字典树上跑完之后,如果后面还有0的转移,就无脑全部跑完。

由于字符集过大,使用unordered_map作为转移。

ac代码:

#include<bits/stdc++.h>

using namespace std;

const int maxn = 2e6 + 5;

int _, n, q, a[5005], b[5005], m[2005], last[2005];

struct Trie {
    unordered_map<int, int> next[maxn];
    bool mark[maxn];
    int sz, root;

    void init() {
        sz = 0;
        root = newNode();
    }

    int newNode() {
        ++sz;
        next[sz].clear();
        mark[sz] = 0;
        return sz;
    }

    int add(int len) {
        int p = root;
        for (int i = 0; i < len; ++i) {
            if (!next[p].count(b[i])) {
                next[p][b[i]] = newNode();
            }
            p = next[p][b[i]];
        }
        return p;
    }

} trie;


list<int>::iterator mp[5005];
list<int> l;

void solve() {
    l.clear();
    for (int i = 0; i < n; ++i) {
        mp[a[i]] = l.end();
    }
    for (int i = 0; i < n; ++i) {
        if (mp[a[i]] != l.end()) {
            l.erase(mp[a[i]]);
        }
        l.push_front(a[i]);
        mp[a[i]] = l.begin();

        int p = trie.root;
        for (auto e:l) {
            if (!trie.next[p].count(e)) {
                break;
            }
            p = trie.next[p][e];
            trie.mark[p] = 1;
        }
        while(trie.next[p].count(0)){
            p = trie.next[p][0];
            trie.mark[p] = 1;
        }
    }

    for (int i = 0; i < q; ++i) {
        if (trie.mark[last[i]]) {
            printf("Yes\n");
        } else {
            printf("No\n");
        }
    }
}

int main() {
    scanf("%d", &_);
    while (_--) {
        trie.init();
        scanf("%d%d", &n, &q);
        for (int i = 0; i < n; ++i) {
            scanf("%d", &a[i]);
        }
        for (int i = 0; i < q; ++i) {
            scanf("%d", &m[i]);
            for (int j = 0; j < m[i]; ++j) {
                scanf("%d", &b[j]);
            }
            last[i] = trie.add(m[i]);
        }
        solve();
    }
    return 0;
}

/*
1
7 5
4 3 4 2 3 1 4
3 3 2 1
2 2 3
3 3 2 1
4 4 1 3 2
4 3 4 0 0

 */
发布了156 篇原创文章 · 获赞 20 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/Cymbals/article/details/102896091