zoukankan      html  css  js  c++  java
  • ac自动机fail树上按询问建立上跳指针——cf963D

    解法看着吓人,其实就是为了优化ac自动机上暴力跳fail指针。。

    另外这题对于复杂度的分析很有学习价值

    /*
    给定一个母串s,再给定n个询问(k,m) 
    对于每个询问,求出长度最小的t,使t是s的子串,且m作为子串在t中出现了m次
    
    对多串建立ac自动机,然后用s去匹配,把所有询问的出现位置都用vector保存下来
    然后对应每个询问的k进行更新答案 
    
    为了保证复杂度:在跳fail不能暴力向上跳,应该直接用一个指针pre跳到上一个带有询问的点
    这样每次向上跳都让某个询问的vector更新进一个新的值
    由于最多有sqrt(n)个不同的询问串长度,所以以每个s[i]为结尾的可匹配串也只有sqrt(n)个,
    即最多在fail树上跳nsqrt(n)次 
    */
    #include<bits/stdc++.h>
    using namespace std;
    #define N 200005
    
    struct Query{
        vector<int>pos;
        int k,len;
    }q[N];
    char s[N],buf[N];
    int n;
    
    struct Trie{
        int nxt[N][26],fail[N],id[N],pre[N];
        int root,L;
        int newnode(){
            memset(nxt[L],-1,sizeof nxt[L]);
            id[L]=0;
            return L++;
        }
        void init(){L=0;root=newnode();}
        void insert(char buf[],int ID){
            int len=strlen(buf);
            int now=root;
            for(int i=0;i<len;i++){
                if(nxt[now][buf[i]-'a']==-1)
                    nxt[now][buf[i]-'a']=newnode();
                now=nxt[now][buf[i]-'a'];
            }
            id[now]=ID;
        }
        void build(){
            queue<int>q;
            fail[root]=root;
            for(int i=0;i<26;i++)
                if(nxt[root][i]==-1)
                    nxt[root][i]=root;
                else {
                    fail[nxt[root][i]]=root;
                    q.push(nxt[root][i]);
                }
            pre[root]=0;
            
            while(q.size()){
                int now=q.front();q.pop();//此时now的fail已经建立好 
                if(id[fail[now]]!=0)//找上一个询问的位置 
                    pre[now]=fail[now];
                else 
                    pre[now]=pre[fail[now]];
                
                for(int i=0;i<26;i++)
                    if(nxt[now][i]==-1)
                        nxt[now][i]=nxt[fail[now]][i];
                    else {
                        fail[nxt[now][i]]=nxt[fail[now]][i];
                        q.push(nxt[now][i]);
                    }
            }
        }
        
        void query(char *s){
            int len=strlen(s);
            int now=root;
            for(int i=0;i<len;i++){
                now=nxt[now][s[i]-'a'];
                //通过pre向上跳
                int p=now;
                while(p){
                    q[id[p]].pos.push_back(i);
                    p=pre[p];
                } 
            }
            
        }
    }ac;
    
    int main(){
        ac.init();
        scanf("%s",s);
        cin>>n;
        for(int i=1;i<=n;i++){
            scanf("%d%s",&q[i].k,buf);
            q[i].len=strlen(buf);
            ac.insert(buf,i);
        }
        ac.build();
        ac.query(s);
    
    //for(int i=1;i<=ac.L;i++)
    //    cout<<ac.pre[i]<<" ";
    
        //处理每个询问 
        for(int i=1;i<=n;i++){
    //cout<<q[i].pos.size()<<"
    ";
            if(q[i].pos.size()<q[i].k){
                puts("-1");continue;
            }
            
            int ans=0x3f3f3f3f;
            for(int j=q[i].k-1;j<q[i].pos.size();j++){
                ans=min(ans,q[i].pos[j]-q[i].pos[j-q[i].k+1]+q[i].len);
            }
            cout<<ans<<'
    '; 
        }
    }
    /*
    
    aaabbbbaaabababab
    27
    2 aaabbbbaaaba
    2 baaabab
    1 abbbbaaabab
    1 aabbbbaaabab
    6 a
    1 aaabbbbaaabababab
    2 aaba
    2 abbbba
    5 aa
    2 aaabbbb
    2 abababa
    3 aba
    2 baaa
    2 bbaaababa
    1 aaabab
    1 abbb
    1 bbbbaaabababa
    1 baaab
    1 abbbbaaabababa
    1 aaababa
    1 ababab
    2 abb
    2 baaabababa
    1 bbaaabababa
    2 aaabb
    1 abababab
    4 bab
    
    
    
    */
  • 相关阅读:
    Attribute特性 与 Reflection反射技术
    星星评分控件----------WebForm服务器控件开发系列
    CheckBox美化控件----------WinForm控件开发系列
    RadioButton美化控件----------WinForm控件开发系列
    分割线控件----------WinForm控件开发系列
    mysql数据库中自增ID不自增1的解决办法
    [WPF] 操作DataGrid单元格
    [WPF] DataGrid单元格中的TextBox绑定数据源
    WPF中同类型实体间的消息推送
    C#获取屏幕工作区大小
  • 原文地址:https://www.cnblogs.com/zsben991126/p/11701240.html
Copyright © 2011-2022 走看看