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 }
  • 相关阅读:
    算法训练 表达式计算
    基础练习 十六进制转十进制
    基础练习 十六进制转十进制
    基础练习 十六进制转十进制
    New ways to verify that Multipath TCP works through your network
    TCP的拥塞控制 (Tahoe Reno NewReno SACK)
    Multipath TCP Port for Android 4.1.2
    How to enable ping response in windows 7?
    NS3
    Multipath TCP Port for Android
  • 原文地址:https://www.cnblogs.com/blog-Dr-J/p/9681821.html
Copyright © 2011-2022 走看看