2019CCPC哈尔滨 L LRU Algorithm(字符串hash)

题意:

题目背景:cache的LRU算法。给定一串长度为n的cache访问序列,多个询问q,每次给mi,表示cache的容量为mi,然后mi个数的序列,问是否存在cache表为这个序列的情况。

题目有多组输入。n<=5000,q<=5000, \(\sum n<=20000,\sum q<=20000,\sum mi<=1e6\)

思路:

按照LRU算法的规律可以很容易发现,对于第i次访问,cache表中的数就是从访问序列第i位往前推,每次未出现的数就加入cache表下一位即可,而cache表的容量大小只是将得到的序列进行截断而已,因此可以预处理出所有位向前推到第1位(假设最多数字种类数为len),1-len所有容量大小所对应的字符串哈希值,时间复杂度为\(O(n^2)\)

每次查询,首先将末尾的0去掉,如果剩余长度l为0,则直接输出yes,否则遍历1-n所有位长度为l的哈希值,若相同则输出Yes(可以再O(N)扫一边确认是否真的相同),若均不相同则输出NO

代码:

#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int maxn=5e3+5;
int seed=13331;
ull has[maxn][maxn];
int a[maxn];
int x[maxn];
int vis[maxn];
void init(int n){
    memset(vis,0,sizeof(int)*(n+1));
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++)has[i][j]=0;
    }
}
int main () {
    int T;
    scanf("%d",&T);
    while(T--){
        int n,q;
        scanf("%d%d",&n,&q);
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
        }
        init(n);
        for(int i=1;i<=n;i++){
            int cnt=0;
            for(int j=i;j>=1;j--){
                if(vis[a[j]]!=i){
                    cnt++;
                    has[i][cnt]=has[i][cnt-1]*seed+a[j];
                    vis[a[j]]=i;
                }
            }
        }
        while(q--){
            int mi;
            scanf("%d",&mi);
            for(int i=1;i<=mi;i++){
                scanf("%d",&x[i]);
            }
            while(x[mi]==0)mi--;
            if(mi==0){
                puts("Yes");
                continue;
            }
            ull hasx=0;
            for(int i=1;i<=mi;i++){
                hasx=hasx*seed+x[i];
            }
            int flag=0;
            for(int i=1;i<=n;i++){
                if(has[i][mi]==hasx){
                    memset(vis,0,sizeof(int)*(n+1));
                    int ok=1;
                    int cnt=0;
                    for(int j=i;j>=1 && cnt<mi;j--){
                        if(!vis[a[j]]){
                            if(a[j]!=x[++cnt]){
                                ok=0;
                                break;
                            }
                            vis[a[j]]=1;
                        }
                    }
                    if(ok){
                        puts("Yes");
                        flag=1;
                        break;
                    }
                }
            }
            if(!flag){
                puts("No");
            }
        }
    }
}
posted @ 2020-10-04 11:53  UCPRER  阅读(192)  评论(0编辑  收藏  举报