1. 程式人生 > 實用技巧 >2019CCPC哈爾濱 L LRU Algorithm(字串hash)

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");
            }
        }
    }
}