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学长·。

代码:

 #include<map>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
char xB[<<],*xS=xB,*xTT=xB;
#define getc() (xS==xTT&&(xTT=(xS=xB)+fread(xB,1,1<<15,stdin),xS==xTT)?0:*xS++)
#define isd(c) (c>='0'&&c<='9')
inline int read(){
char xchh;
int xaa;
while(xchh=getc(),!isd(xchh));(xaa=xchh-'');
while(xchh=getc(),isd(xchh))xaa=xaa*+xchh-'';
return xaa;
}
using std::map;
using std::queue;
using std::vector;
typedef unsigned int uit;
struct trnt{
map<int,int>ch;
int fl;
vector<int>fin;
int vis;
}tr[];
struct idt{
int la,lb;
vector<int>a;
vector<int>b;
int ans;
void Ins(void)
{
scanf("%d",&la);
for(int i=;i<=la;i++)
{
int tt;
scanf("%d",&tt);
a.push_back(tt);
}
scanf("%d",&lb);
for(int i=;i<=lb;i++)
{
int tt;
scanf("%d",&tt);
b.push_back(tt);
}
return ;
}
}cat[];
int num[];
bool usd[];
int n,m;
int siz;
int len;
queue<int>Q;
vector<int>hre;
void Insert(int k)
{
int len;
int c;
int root=;
scanf("%d",&len);
for(int i=;i<=len;i++)
{
scanf("%d",&c);
if(tr[root].ch.find(c)==tr[root].ch.end())
tr[root].ch[c]=++siz;
root=tr[root].ch[c];
}
tr[root].fin.push_back(k);
return ;
}
void Build(void)
{
int root=;
for(map<int,int>::iterator j=tr[root].ch.begin();j!=tr[root].ch.end();j++)
{
int sn=j->second;
tr[sn].fl=;
Q.push(sn);
}
while(!Q.empty())
{
root=Q.front();
Q.pop();
for(map<int,int>::iterator j=tr[root].ch.begin();j!=tr[root].ch.end();j++)
{
int i=j->first;
int sn=j->second;
int nxt=tr[root].fl;
while(nxt&&tr[nxt].ch.find(i)==tr[nxt].ch.end())
nxt=tr[nxt].fl;
if(tr[nxt].ch.find(i)!=tr[nxt].ch.end())
nxt=tr[nxt].ch[i];
tr[sn].fl=nxt;
Q.push(sn);
}
}
return;
}
void Query(int p)
{
int root;
root=;
for(uit i=;i<cat[p].a.size();i++)
{
int c=cat[p].a[i];
while(root&&tr[root].ch.find(c)==tr[root].ch.end())
root=tr[root].fl;
if(tr[root].ch.find(c)!=tr[root].ch.end())
{
root=tr[root].ch[c];
int nxt=root;
while(nxt)
{
if(tr[nxt].vis==p)
break;
tr[nxt].vis=p;
for(uit l=;l<tr[nxt].fin.size();l++)
{
int f=tr[nxt].fin[l];
if(!usd[f])
{
usd[f]=true;
hre.push_back(f);
cat[p].ans++;
num[f]++;
}
}
nxt=tr[nxt].fl;
}
}
}
root=;
for(uit i=;i<cat[p].b.size();i++)
{
int c=cat[p].b[i];
while(root&&tr[root].ch.find(c)==tr[root].ch.end())
root=tr[root].fl;
if(tr[root].ch.find(c)!=tr[root].ch.end())
{
root=tr[root].ch[c];
int nxt=root;
while(nxt)
{
if(tr[nxt].vis==p)
break;
tr[nxt].vis=p;
for(uit l=;l<tr[nxt].fin.size();l++)
{
int f=tr[nxt].fin[l];
if(!usd[f])
{
usd[f]=true;
hre.push_back(f);
cat[p].ans++;
num[f]++;
}
}
nxt=tr[nxt].fl;
}
}
}
for(uit i=;i<hre.size();i++)
usd[hre[i]]=false;
hre.clear();
return ;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++)
cat[i].Ins();
for(int i=;i<=m;i++)
Insert(i);
Build();
for(int i=;i<=n;i++)
Query(i);
for(int i=;i<=m;i++)
printf("%d\n",num[i]);
for(int i=;i<=n;i++)
printf("%d ",cat[i].ans);
return ;
}

2.广义后缀自动机

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

代码:

 #include<map>
#include<cstdio>
#include<cstring>
#include<algorithm>
struct sant{
std::map<int,int>tranc;
int len;
int pre;
}s[];
struct pnt{
int wgt;
int vis;
int tms;
}p[];
int cnt;
int siz;
int fin;
int n,m;
int lenfname[];
int lensname[];
int str[];
void Insert(int c)
{
int nwp,nwq,lsp,lsq;
nwp=++siz;
s[nwp].len=s[fin].len+;
for(lsp=fin;lsp&&(s[lsp].tranc.find(c)==s[lsp].tranc.end());lsp=s[lsp].pre)
s[lsp].tranc[c]=nwp;
if(!lsp)
s[nwp].pre=;
else{
lsq=s[lsp].tranc[c];
if(s[lsq].len==s[lsp].len+)
s[nwp].pre=lsq;
else{
nwq=++siz;
s[nwq]=s[lsq];
s[nwq].len=s[lsp].len+;
s[nwp].pre=s[lsq].pre=nwq;
while((s[lsp].tranc.find(c)!=s[lsp].tranc.end())&&s[lsp].tranc[c]==lsq)
{
s[lsp].tranc[c]=nwq;
lsp=s[lsp].pre;
}
}
}
fin=nwp;
return ;
}
void mark(int plc,int times)
{
if(!plc)
return ;
if(p[plc].vis==times)
return ;
p[plc].vis=times;
p[plc].wgt++;
mark(s[plc].pre,times);
return ;
}
int take(int plc,int times)
{
if(!plc)
return ;
if(p[plc].vis==times)
return ;
p[plc].vis=times;
return p[plc].tms+take(s[plc].pre,times);
}
int main()
{
fin=++siz;
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++)
{
fin=;
scanf("%d",&lenfname[i]);
for(int j=;j<=lenfname[i];j++)
{
cnt++;
scanf("%d",&str[cnt]);
Insert(str[cnt]);
}
fin=;
scanf("%d",&lensname[i]);
for(int j=;j<=lensname[i];j++)
{
cnt++;
scanf("%d",&str[cnt]);
Insert(str[cnt]);
}
}
cnt=;
for(int i=;i<=n;i++)
{
int root;
root=;
for(int j=;j<=lenfname[i];j++)
{
cnt++;
root=s[root].tranc[str[cnt]];
mark(root,i);
}
root=;
for(int j=;j<=lensname[i];j++)
{
cnt++;
root=s[root].tranc[str[cnt]];
mark(root,i);
}
}
for(int i=;i<=m;i++)
{
int len;
int tmp;
scanf("%d",&len);
int root=;
for(int j=;j<=len;j++)
{
scanf("%d",&tmp);
if(!root)
continue;
if(s[root].tranc.find(tmp)!=s[root].tranc.end())
root=s[root].tranc[tmp];
else
root=;
}
printf("%d\n",p[root].wgt);
p[root].tms++;
}
cnt=;
for(int i=;i<=n;i++)
{
int ans=;
int root;
root=;
for(int j=;j<=lenfname[i];j++)
{
cnt++;
root=s[root].tranc[str[cnt]];
ans+=take(root,i+n);
}
root=;
for(int j=;j<=lensname[i];j++)
{
cnt++;
root=s[root].tranc[str[cnt]];
ans+=take(root,i+n);
}
printf("%d ",ans);
}
puts("");
return ;
}

BZOJ2754: [SCOI2012]喵星球上的点名(AC自动机/后缀自动机)的更多相关文章

  1. BZOJ2754: [SCOI2012]喵星球上的点名(AC自动机)

    Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 2816  Solved: 1246[Submit][Status][Discuss] Descript ...

  2. [BZOJ2754] [SCOI2012]喵星球上的点名解题报告|后缀数组

    a180285幸运地被选做了地球到喵星球的留学生.他发现喵星人在上课前的点名现象非常有趣.   假设课堂上有N个喵星人,每个喵星人的名字由姓和名构成.喵星球上的老师会选择M个串来点名,每次读出一个串的 ...

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

    2754: [SCOI2012]喵星球上的点名 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 1902  Solved: 837[Submit][St ...

  4. BZOJ2754: [SCOI2012]喵星球上的点名

    2754: [SCOI2012]喵星球上的点名 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 680  Solved: 314[Submit][Sta ...

  5. bzoj2754:[SCOI2012]喵星球上的点名(后缀自动机)

    Description a180285幸运地被选做了地球到喵星球的留学生.他发现喵星人在上课前的点名现象非常有趣.   假设课堂上有N个喵星人,每个喵星人的名字由姓和名构成.喵星球上的老师会选择M个串 ...

  6. BZOJ 2754 [SCOI2012]喵星球上的点名 (AC自动机、树状数组)

    吐槽: 为啥很多人用AC自动机暴力跳都过了?复杂度真的对么? 做法一: AC自动机+树状数组 姓名的问题,中间加个特殊字符连起来即可. 肯定是对点名串建AC自动机(map存儿子),然后第一问就相当于问 ...

  7. BZOJ2754 SCOI2012喵星球上的点名

    绝世好题. 正当我犹豫不决时,hzwer说:“MAP!!!” 没错这题大大的暴力,生猛的stl,贼基尔爽,,ԾㅂԾ,, 由于我们求点名在名字中的子串个数,所以将点名建AC自动机,记录节点属于哪次点名, ...

  8. BZOJ 2754 [SCOI2012]喵星球上的点名 (AC自动机+map维护Trie树)

    题目大意:略 由于字符集大,要用map维护Trie树 并不能用AC自动机的Trie图优化,不然内存会炸 所以我用AC自动机暴跳fail水过的 显然根据喵星人建AC自动机是不行的,所以要根据问题建 然而 ...

  9. BZOJ2754 [SCOI2012]喵星球上的点名 SA+莫队+树状数组

    题面 戳这里 题解 首先先把所有给出的姓名和询问全部接在一起,建出\(height\)数组. 某个串要包含整个询问串,其实就相当于某个串与询问串的\(lcp\)为询问串的长度. 而两个后缀\(Suff ...

随机推荐

  1. (hdu step 7.2.1)The Euler function(欧拉函数模板题——求phi[a]到phi[b]的和)

    题目: The Euler function Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Othe ...

  2. Go 语言编程

    [课程名称]Go 语言编程   [课程时间]2014年7月30日(周三) 20:50 - 22:00         [课程安排]20:50-21:00     通过邮件地址登录网络课堂       ...

  3. vim基础学习之EX命令

    :tabnew -创建新标签 :split(sp)-垂直分割窗口 如果没有打开新的文件,那么会打开原来窗口的文件 :vsplit(vsp)-水平分割窗口 如果没有打开新的文件,那么会打开原来窗口的文件 ...

  4. WebServic调用天气预报服务

    在项目开发中,我们除了发布WebService提供客户调用外,也经常需要调用一些客户或者第三方的WebService服务,这里就通过一个Demo来演示调用一个第三方的天气预报服务. 1.天气预报服务接 ...

  5. 15.C语言多线程实现变色龙以及cmd窗口标题变化

    #define _CRT_SECURE_NO_WARNINGS #include <stdlib.h> #include <stdio.h> #include <Wind ...

  6. HDU 5358 First One 数学+尺取法

    多校的题,摆明了数学题,但是没想出来,蠢爆了,之前算了半天的s[i][j]的和,其实是积.其实比赛的时候我连log(s[i][j])+1是s[i][j]的位数都没看出来,说出来都丢人. 知道了这个之后 ...

  7. MySql免安装版绿化版安装配置,附MySQL服务无法启动解决方案

    整理于:https://www.cnblogs.com/cenwei/p/6249856.html      我下载的MySQL版本是:mysql-5.6.15-winx64 一.解压文件 下载好My ...

  8. DOM操作系列-01

    ]常见事件: //onclick     点击时触发事件. //ondblclick    双击时触发事件. //onkeydown   按键按下 //onkeypress   点击按键 //onke ...

  9. WP8 学习笔记(002_应用程序结构)

    下图是微软官方给出的WP8应用程序执行顺序: 在App.XAML.CS中,有程序主要步骤的函数 // 应用程序启动(例如,从“开始”菜单启动)时执行的代码 // 此代码在重新激活应用程序时不执行 pr ...

  10. 利用js 获取ip和地址

    1.引用第三方js<script src="http://pv.sohu.com/cityjson?ie=utf-8"></script> 2.     I ...