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


    Description

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

    解题报告

    这题可以暴力水,直接上AC自动机+map
    对于每一个数字开节点,map当next数组,然后暴力统计即可,注意构建fail时采用遍历map的方式,不能枚举10000.
    对于统计:
    关键点节点开vector存是哪几次点名,不能朴素的直接合并和压缩,每一次跳fail链遍历vector,注意可以打vis标记,注意清空常数

    #include <algorithm>
    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include <cstdio>
    #include <vector>
    #include <cmath>
    #include <queue>
    #include <map>
    #define RG register
    #define il inline
    #define iter iterator
    #define Max(a,b) ((a)>(b)?(a):(b))
    #define Min(a,b) ((a)<(b)?(a):(b))
    using namespace std;
    const int N=500005,M=200005;
    map<int,int>a[N];vector<int>vc[N];
    vector<int>fir[M][2];
    int n,m,cnt=0,root=0;int s[N],fail[N];
    void add(int len,int id){
       int p=root;
       for(int i=1;i<=len;i++){
          if(a[p].count(s[i]))p=a[p][s[i]];
          else a[p][s[i]]=++cnt,p=cnt;
       }
       vc[p].push_back(id);
    }
    map<int,int>::iter it;queue<int>q;
    void getfail(){
       int x,u,now;
       q.push(root);
       while(!q.empty()){
          x=q.front();q.pop();
          for(it=a[x].begin();it!=a[x].end();it++){
             int i=it->first;
             u=fail[x];now=it->second;
             while(u && !a[u].count(i))u=a[u][i];
             if(a[u].count(i) && now!=a[u][i])fail[now]=a[u][i];
             q.push(now);
          }
       }
    }
    int ans[N],app[N],st[N],top=0,stt[N],toper=0;bool d[N],vis[N];
    void clac(int x,int id){
       int u;
       while(x){
          if(vis[x])break;
          int sz=vc[x].size();vis[x]=true;stt[++toper]=x;
          for(int j=0;j<sz;j++){
             u=vc[x][j];
             if(!d[u]){d[u]=true;ans[u]++;app[id]++;st[++top]=u;}
          }
          x=fail[x];
       }
    }
    void solve(int id){
       int len,i,p=root;top=0;
       for(int k=0;k<=1;k++)
       {
          len=fir[id][k].size();p=root;
          for(int H=0;H<len;H++){
             i=fir[id][k][H];
             while(p && (!a[p].count(i) || !a[p][i]))p=fail[p];
             p=a[p][i];
             clac(p,id);
          }
       }
       while(top)d[st[top--]]=false;
       while(toper)vis[stt[toper--]]=false;
    }
    void work()
    {
       int len,x;
       scanf("%d%d",&n,&m);
       for(int i=1;i<=n;i++){
          for(int k=0;k<=1;k++)
          {
             scanf("%d",&len);
             for(int j=1;j<=len;j++)
                scanf("%d",&x),fir[i][k].push_back(x);
          }
       }
       for(int i=1;i<=m;i++){
          scanf("%d",&len);
          for(int j=1;j<=len;j++)scanf("%d",&s[j]);
          add(len,i);
       }
       getfail();
       for(int i=1;i<=n;i++)solve(i);
       for(int i=1;i<=m;i++)printf("%d
    ",ans[i]);
       printf("%d",app[1]);for(int i=2;i<=n;i++)printf(" %d",app[i]);
    }
    int main(){work();return 0;}
    
    
  • 相关阅读:
    Golang手动分页,按等份拆分数据
    GORM无法映射到结构体上
    VSCODE GOLANG运行多个服务
    解决,MAVEN
    Properties配置文件常见错误写法以及转义字符说明
    Pentaho Data Integration (PDI/Kettle)与Java版本支持关系
    MYSQL之读写分离搭建方案
    Windows下创建软件快速启动命令
    Sonar的一些使用总结
    使用SVG Path绘图
  • 原文地址:https://www.cnblogs.com/Yuzao/p/7636955.html
Copyright © 2020-2023  润新知