• BZOJ 2754: [SCOI2012]喵星球上的点名 [AC自动机+map+暴力]


    2754: [SCOI2012]喵星球上的点名

    Time Limit: 20 Sec  Memory Limit: 128 MB
    Submit: 1902  Solved: 837
    [Submit][Status][Discuss]

    Description

    a180285幸运地被选做了地球到喵星球的留学生。他发现喵星人在上课前的点名现象非常有趣。   假设课堂上有N个喵星人,每个喵星人的名字由姓和名构成。喵星球上的老师会选择M个串来点名,每次读出一个串的时候,如果这个串是一个喵星人的姓或名的子串,那么这个喵星人就必须答到。 然而,由于喵星人的字码过于古怪,以至于不能用ASCII码来表示。为了方便描述,a180285决定用数串来表示喵星人的名字。
    现在你能帮助a180285统计每次点名的时候有多少喵星人答到,以及M次点名结束后每个喵星人答到多少次吗?  

    Input

    现在定义喵星球上的字符串给定方法:
    先给出一个正整数L,表示字符串的长度,接下来L个整数表示字符串的每个字符。
    输入的第一行是两个整数N和M。
    接下来有N行,每行包含第i 个喵星人的姓和名两个串。姓和名都是标准的喵星球上的
    字符串。
    接下来有M行,每行包含一个喵星球上的字符串,表示老师点名的串。

    Output

    对于每个老师点名的串输出有多少个喵星人应该答到。
    然后在最后一行输出每个喵星人被点到多少次。

    HINT

    【数据范围】 

    对于30%的数据,保证: 

    1<=N,M<=1000,喵星人的名字总长不超过4000,点名串的总长不超过2000。

    对于100%的数据,保证:

    1<=N<=20000,1<=M<=50000,喵星人的名字总长和点名串的总长分别不超过100000,保证喵星人的字符串中作为字符存在的数不超过10000。


    喵~ http://www.cnblogs.com/candy99/p/cat.html


    首先想到两问建两个AC自动机,第一问是把喵名建自动机然后点名串统计fail子树,但是不对啊啊啊啊啊人家一个喵就算一次.....


    所以就发现其他人用了个很暴力的方法,点名串建AC自动机然后喵在上面跑,每跑一个字符暴力统计更新fail指向的点名串......然后就过了

    一些细节:

    1.要用map  字符集太大(离散化并没有用) 这样建AC自动机的时候就不能用Trie图优化了用普通做法

    2.一个喵统计点名串需要用个vis[],从黄学长哪里学到了黑科技用个vector记录vis了那些,不用memset直接把vector里的还原行了

    3.可能有重复点名串!!!!!

    4.姓和名用个特殊数字连起来行了 

    980ms

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <vector>
    #include <map>
    using namespace std;
    const int N=1e5+5,INF=1e9;
    inline int read(){
        char c=getchar();int x=0,f=1;
        while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0'; c=getchar();}
        return x*f;
    }
    
    int n,m,k;
    vector<int> a[N];
    struct node{
        map<int,int> ch;
        int fail,val;
        vector<int> s;
    }t[N];
    int sz;
    void ins(int id){
        int u=0,n=read();
        for(int i=1;i<=n;i++){
            int c=read();
            if(!t[u].ch[c]) t[u].ch[c]=++sz;
            u=t[u].ch[c];
        }
        t[u].s.push_back(id);
    }
    int q[N],head,tail;
    map<int,int>::iterator it,it2;
    void getAC(){
        head=tail=1;
        for(it=t[0].ch.begin();it!=t[0].ch.end();it++)
            q[tail++]=it->second;
        while(head!=tail){
            int u=q[head++];
            for(it=t[u].ch.begin();it!=t[u].ch.end();it++){
                int v=it->second,c=it->first;
                int now=t[u].fail;
                while(now&&!t[now].ch.count(c)) now=t[now].fail;
                if(t[now].ch.count(c)) t[v].fail=t[now].ch[c];
                else t[v].fail=now;//0
                q[tail++]=v;
            }
        }
    }
    
    int a1[N],a2[N];
    bool vis[N];
    vector<int> V;
    void update(int u,int id){
        for(;u;u=t[u].fail){
            if(vis[u]) break;
            vis[u]=1;
            V.push_back(u);
            for(int i=0;i<t[u].s.size();i++)
                a1[t[u].s[i]]++,a2[id]++;
        }
    }
    void runAC(int id){
        vector<int> &s=a[id];
        int u=0,n=s.size();
        for(int i=0;i<n;i++){
            while(u&&!t[u].ch.count(s[i])) u=t[u].fail;
            if(t[u].ch.count(s[i])) u=t[u].ch[s[i]];
            update(u,id);
        }
        for(int i=0;i<V.size();i++) vis[V[i]]=0;
        V.clear();
    }
    void solve(){
        getAC();
        for(int i=1;i<=n;i++) runAC(i); 
        for(int i=1;i<=m;i++) printf("%d
    ",a1[i]);
        for(int i=1;i<=n;i++) {printf("%d",a2[i]);if(i!=n) putchar(' ');}
    }
    int main(){
        freopen("in","r",stdin);
        n=read();m=read();
        for(int i=1;i<=n;i++){
            k=read();while(k--) a[i].push_back(read());
            a[i].push_back(-1);
            k=read();while(k--) a[i].push_back(read());
        }
        for(int i=1;i<=m;i++) ins(i);
        solve();
    }
    View Code
  • 相关阅读:
    我把问烂了的⭐MySQL⭐面试题总结了一下(带答案,万字总结,精心打磨,建议收藏)
    在高并发情况下我是这样解决单用户超领优惠券问题
    js 数组去重十几种解法,基础知识扎实吗?(附数组方法)
    Jackson 解析 JSON 详细教程
    解锁各种js数组骚操作,总有你想要的!
    JS 异步编程的 5 种解决方案
    YARN 架构设计 和 RPC 网络通信
    基于消息队列构建实时大数据日志分析系统_没用
    Java:List转Map (用stream实现)
    Java时间格式:yyyymmdd转换为yyyy年mm月dd日
  • 原文地址:https://www.cnblogs.com/candy99/p/6371576.html
Copyright © 2020-2023  润新知