zoukankan      html  css  js  c++  java
  • BZOJ2754: [SCOI2012]喵星球上的点名(AC自动机/后缀自动机)

    Description

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

    Input

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

    Output

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

    Sample Input

    2 3
    6 8 25 0 24 14 8 6 18 0 10 20 24 0
    7 14 17 8 7 0 17 0 5 8 25 0 24 0
    4 8 25 0 24
    4 7 0 17 0
    4 17 0 8 25

    Sample Output

    2
    1
    0
    1 2

    解题思路:

    1、AC自动机

    首先,我是从来不用AC自动机的,直到看到了这道题。

    Trie图构建时需要承受枚举字符集的复杂度,在匹配{a~z}时还只是一个26的常数在这道题变得不可承受。

    所以就不能进行图没有儿子时的构建。

    那么就是AC自动机了。

    map存儿子。

    vector存名字。

    很少使用STL选手当场死亡。

    向dalao请教map枚举元素的方法。

    结果一直WA

    最后才知道可能会有重复的询问QAQ拿vector存一下。

    致敬hzwer学长·。

    代码:

      1 #include<map>
      2 #include<queue>
      3 #include<cstdio>
      4 #include<vector>
      5 #include<cstring>
      6 #include<algorithm>
      7 char xB[1<<15],*xS=xB,*xTT=xB;
      8 #define getc() (xS==xTT&&(xTT=(xS=xB)+fread(xB,1,1<<15,stdin),xS==xTT)?0:*xS++)
      9 #define isd(c) (c>='0'&&c<='9')
     10 inline int read(){
     11     char xchh;
     12     int xaa;
     13     while(xchh=getc(),!isd(xchh));(xaa=xchh-'0');
     14     while(xchh=getc(),isd(xchh))xaa=xaa*10+xchh-'0';
     15     return xaa;
     16 }
     17 using std::map;
     18 using std::queue;
     19 using std::vector;
     20 typedef unsigned int uit;
     21 struct trnt{
     22     map<int,int>ch;
     23     int fl;
     24     vector<int>fin;
     25     int vis;
     26 }tr[600000];
     27 struct idt{
     28     int la,lb;
     29     vector<int>a;
     30     vector<int>b;
     31     int ans;
     32     void Ins(void)
     33     {
     34         scanf("%d",&la);
     35         for(int i=1;i<=la;i++)
     36         {
     37             int tt;
     38             scanf("%d",&tt);
     39             a.push_back(tt);
     40         }
     41         scanf("%d",&lb);
     42         for(int i=1;i<=lb;i++)
     43         {
     44             int tt;
     45             scanf("%d",&tt);
     46             b.push_back(tt);
     47         }
     48         return ;
     49     }
     50 }cat[1000000];
     51 int num[1000000];
     52 bool usd[1000000];
     53 int n,m;
     54 int siz;
     55 int len;
     56 queue<int>Q;
     57 vector<int>hre;
     58 void Insert(int k)
     59 {
     60     int len;
     61     int c;
     62     int root=0;
     63     scanf("%d",&len);
     64     for(int i=1;i<=len;i++)
     65     {
     66         scanf("%d",&c);
     67         if(tr[root].ch.find(c)==tr[root].ch.end())
     68             tr[root].ch[c]=++siz;
     69         root=tr[root].ch[c];
     70     }
     71     tr[root].fin.push_back(k);
     72     return ;
     73 }
     74 void Build(void)
     75 {
     76     int root=0;
     77     for(map<int,int>::iterator j=tr[root].ch.begin();j!=tr[root].ch.end();j++)
     78     {
     79         int sn=j->second;
     80         tr[sn].fl=0;
     81         Q.push(sn);
     82     }
     83     while(!Q.empty())
     84     {
     85         root=Q.front();
     86         Q.pop();
     87         for(map<int,int>::iterator j=tr[root].ch.begin();j!=tr[root].ch.end();j++)
     88         {
     89             int i=j->first;
     90             int sn=j->second;
     91             int nxt=tr[root].fl;
     92             while(nxt&&tr[nxt].ch.find(i)==tr[nxt].ch.end())
     93                 nxt=tr[nxt].fl;
     94             if(tr[nxt].ch.find(i)!=tr[nxt].ch.end())
     95                 nxt=tr[nxt].ch[i];
     96             tr[sn].fl=nxt;
     97             Q.push(sn);
     98         }
     99     }
    100     return;
    101 }
    102 void Query(int p)
    103 {
    104     int root;
    105     root=0;
    106     for(uit i=0;i<cat[p].a.size();i++)
    107     {
    108         int c=cat[p].a[i];
    109         while(root&&tr[root].ch.find(c)==tr[root].ch.end())
    110             root=tr[root].fl;
    111         if(tr[root].ch.find(c)!=tr[root].ch.end())
    112         {
    113             root=tr[root].ch[c];
    114             int nxt=root;
    115             while(nxt)
    116             {
    117                 if(tr[nxt].vis==p)
    118                     break;
    119                 tr[nxt].vis=p;
    120                 for(uit l=0;l<tr[nxt].fin.size();l++)
    121                 {
    122                     int f=tr[nxt].fin[l];
    123                     if(!usd[f])
    124                     {
    125                         usd[f]=true;
    126                         hre.push_back(f);
    127                         cat[p].ans++;
    128                         num[f]++;
    129                     }
    130                 }
    131                 nxt=tr[nxt].fl;
    132             }
    133         }
    134     }
    135     root=0;
    136     for(uit i=0;i<cat[p].b.size();i++)
    137     {
    138         int c=cat[p].b[i];
    139         while(root&&tr[root].ch.find(c)==tr[root].ch.end())
    140             root=tr[root].fl;
    141         if(tr[root].ch.find(c)!=tr[root].ch.end())
    142         {
    143             root=tr[root].ch[c];
    144             int nxt=root;
    145                while(nxt)
    146             {
    147                 if(tr[nxt].vis==p)
    148                     break;
    149                 tr[nxt].vis=p;
    150                 for(uit l=0;l<tr[nxt].fin.size();l++)
    151                 {
    152                     int f=tr[nxt].fin[l];
    153                     if(!usd[f])
    154                     {
    155                         usd[f]=true;
    156                         hre.push_back(f);
    157                         cat[p].ans++;
    158                         num[f]++;
    159                     }
    160                 }
    161                 nxt=tr[nxt].fl;
    162             }
    163         }
    164     }
    165     for(uit i=0;i<hre.size();i++)
    166         usd[hre[i]]=false;
    167        hre.clear();
    168     return ;
    169 }
    170 int main()
    171 {
    172     scanf("%d%d",&n,&m);
    173     for(int i=1;i<=n;i++)
    174         cat[i].Ins();
    175     for(int i=1;i<=m;i++)
    176         Insert(i);
    177     Build();
    178     for(int i=1;i<=n;i++)
    179         Query(i);
    180     for(int i=1;i<=m;i++)
    181         printf("%d
    ",num[i]);
    182     for(int i=1;i<=n;i++)
    183         printf("%d ",cat[i].ans);
    184     return 0;
    185 }

     2.广义后缀自动机

    只需要先建广义后缀自动机,在pre节点上打好标记,在查询时查询节点的标记就好了。 第二问只需在询问结束节点打标记遍历子串就好了。

    代码:

      1 #include<map>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<algorithm>
      5 struct sant{
      6     std::map<int,int>tranc;
      7     int len;
      8     int pre;
      9 }s[2000000];
     10 struct pnt{
     11     int wgt;
     12     int vis;
     13     int tms;
     14 }p[2000000];
     15 int cnt;
     16 int siz;
     17 int fin;
     18 int n,m;
     19 int lenfname[1000000];
     20 int lensname[100000];
     21 int str[100001];
     22 void Insert(int c)
     23 {
     24     int nwp,nwq,lsp,lsq;
     25     nwp=++siz;
     26     s[nwp].len=s[fin].len+1;
     27     for(lsp=fin;lsp&&(s[lsp].tranc.find(c)==s[lsp].tranc.end());lsp=s[lsp].pre)
     28         s[lsp].tranc[c]=nwp;
     29     if(!lsp)
     30         s[nwp].pre=1;
     31     else{
     32         lsq=s[lsp].tranc[c];
     33         if(s[lsq].len==s[lsp].len+1)
     34             s[nwp].pre=lsq;
     35         else{
     36             nwq=++siz;
     37             s[nwq]=s[lsq];
     38             s[nwq].len=s[lsp].len+1;
     39             s[nwp].pre=s[lsq].pre=nwq;
     40             while((s[lsp].tranc.find(c)!=s[lsp].tranc.end())&&s[lsp].tranc[c]==lsq)
     41             {
     42                 s[lsp].tranc[c]=nwq;
     43                 lsp=s[lsp].pre;
     44             }
     45         }
     46     }
     47     fin=nwp;
     48     return ;
     49 }
     50 void mark(int plc,int times)
     51 {
     52     if(!plc)
     53         return ;
     54     if(p[plc].vis==times)
     55         return ;
     56     p[plc].vis=times;
     57     p[plc].wgt++;
     58     mark(s[plc].pre,times);
     59     return ;
     60 }
     61 int take(int plc,int times)
     62 {
     63     if(!plc)
     64         return 0;
     65     if(p[plc].vis==times)
     66         return 0;
     67     p[plc].vis=times;
     68     return p[plc].tms+take(s[plc].pre,times);
     69 }
     70 int main()
     71 {
     72     fin=++siz;
     73     scanf("%d%d",&n,&m);
     74     for(int i=1;i<=n;i++)
     75     {
     76         fin=1;
     77         scanf("%d",&lenfname[i]);
     78         for(int j=1;j<=lenfname[i];j++)
     79         {
     80             cnt++;
     81             scanf("%d",&str[cnt]);
     82             Insert(str[cnt]);
     83         }
     84         fin=1;
     85         scanf("%d",&lensname[i]);
     86         for(int j=1;j<=lensname[i];j++)
     87         {
     88             cnt++;
     89             scanf("%d",&str[cnt]);
     90             Insert(str[cnt]);
     91         }
     92     }
     93     cnt=0;
     94     for(int i=1;i<=n;i++)
     95     {
     96         int root;
     97         root=1;
     98         for(int j=1;j<=lenfname[i];j++)
     99         {
    100             cnt++;
    101             root=s[root].tranc[str[cnt]];
    102             mark(root,i);
    103         }
    104         root=1;
    105         for(int j=1;j<=lensname[i];j++)
    106         {
    107             cnt++;
    108             root=s[root].tranc[str[cnt]];
    109             mark(root,i);
    110         }
    111     }
    112     for(int i=1;i<=m;i++)
    113     {
    114         int len;
    115         int tmp;
    116         scanf("%d",&len);
    117         int root=1;
    118         for(int j=1;j<=len;j++)
    119         {
    120             scanf("%d",&tmp);
    121             if(!root)
    122                 continue;
    123             if(s[root].tranc.find(tmp)!=s[root].tranc.end())
    124                 root=s[root].tranc[tmp];
    125             else
    126                 root=0;
    127         }
    128         printf("%d
    ",p[root].wgt);
    129         p[root].tms++;
    130     }
    131     cnt=0;
    132     for(int i=1;i<=n;i++)
    133     {
    134         int ans=0;
    135         int root;
    136         root=1;
    137         for(int j=1;j<=lenfname[i];j++)
    138         {
    139             cnt++;
    140             root=s[root].tranc[str[cnt]];
    141             ans+=take(root,i+n);
    142         }
    143         root=1;
    144         for(int j=1;j<=lensname[i];j++)
    145         {
    146             cnt++;
    147             root=s[root].tranc[str[cnt]];
    148             ans+=take(root,i+n);
    149         }
    150         printf("%d ",ans);
    151     }
    152     puts("");
    153     return 0;
    154 }
  • 相关阅读:
    jeecg中移动tbody中的tr可实现位置交换
    SQL Server中的Datediff移植到Oracle计算有误解决方案
    Oracle如何插入日期数据
    在 Oracle 9i 中创建 方案
    手把手教你uniapp 打包的H5怎么实现谷歌登录
    网站和项目的区别
    基础知识
    全球唯一标识GUID
    MVC3 Razor视图引擎基础语法
    缓存技术
  • 原文地址:https://www.cnblogs.com/blog-Dr-J/p/9681821.html
Copyright © 2011-2022 走看看