BZOJ2754: [SCOI2012]喵星球上的点名(AC自动机/后缀自动机)
Description
Input
Output
Sample Input
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
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自动机/后缀自动机)的更多相关文章
- BZOJ2754: [SCOI2012]喵星球上的点名(AC自动机)
Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 2816 Solved: 1246[Submit][Status][Discuss] Descript ...
- [BZOJ2754] [SCOI2012]喵星球上的点名解题报告|后缀数组
a180285幸运地被选做了地球到喵星球的留学生.他发现喵星人在上课前的点名现象非常有趣. 假设课堂上有N个喵星人,每个喵星人的名字由姓和名构成.喵星球上的老师会选择M个串来点名,每次读出一个串的 ...
- BZOJ 2754: [SCOI2012]喵星球上的点名 [AC自动机+map+暴力]
2754: [SCOI2012]喵星球上的点名 Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 1902 Solved: 837[Submit][St ...
- BZOJ2754: [SCOI2012]喵星球上的点名
2754: [SCOI2012]喵星球上的点名 Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 680 Solved: 314[Submit][Sta ...
- bzoj2754:[SCOI2012]喵星球上的点名(后缀自动机)
Description a180285幸运地被选做了地球到喵星球的留学生.他发现喵星人在上课前的点名现象非常有趣. 假设课堂上有N个喵星人,每个喵星人的名字由姓和名构成.喵星球上的老师会选择M个串 ...
- BZOJ 2754 [SCOI2012]喵星球上的点名 (AC自动机、树状数组)
吐槽: 为啥很多人用AC自动机暴力跳都过了?复杂度真的对么? 做法一: AC自动机+树状数组 姓名的问题,中间加个特殊字符连起来即可. 肯定是对点名串建AC自动机(map存儿子),然后第一问就相当于问 ...
- BZOJ2754 SCOI2012喵星球上的点名
绝世好题. 正当我犹豫不决时,hzwer说:“MAP!!!” 没错这题大大的暴力,生猛的stl,贼基尔爽,,ԾㅂԾ,, 由于我们求点名在名字中的子串个数,所以将点名建AC自动机,记录节点属于哪次点名, ...
- BZOJ 2754 [SCOI2012]喵星球上的点名 (AC自动机+map维护Trie树)
题目大意:略 由于字符集大,要用map维护Trie树 并不能用AC自动机的Trie图优化,不然内存会炸 所以我用AC自动机暴跳fail水过的 显然根据喵星人建AC自动机是不行的,所以要根据问题建 然而 ...
- BZOJ2754 [SCOI2012]喵星球上的点名 SA+莫队+树状数组
题面 戳这里 题解 首先先把所有给出的姓名和询问全部接在一起,建出\(height\)数组. 某个串要包含整个询问串,其实就相当于某个串与询问串的\(lcp\)为询问串的长度. 而两个后缀\(Suff ...
随机推荐
- poj--1488--TEX Quotes(水题)
TEX Quotes Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 9672 Accepted: 5071 Descri ...
- Spatial Pyramid Matching
转自:http://blog.csdn.net/jwh_bupt/article/details/9625469 SPM 全称是Spatial Pyramid Matching,出现的背景是bag o ...
- GridView单元格取值显示为
在通过GridView取一个单元格(cell)的值时,数据库中为NULL,而页面上显示为空格.发现通过gridview.cell[i].text取出来的值为 ,导致获取数据出现问题. 解决方法: 一. ...
- tensorflow学习之路----保存和提取数据
#保存数据注意他只能保存变量,不能保存神经网络的框架.#保存数据的作用:保存权重有利于下一次的训练,或者可以用这个数据进行识别#np.arange():arange函数用于创建等差数组,使用频率非常高 ...
- Spring Cloud学习笔记【三】服务消费者Feign
Feign 是一个声明式的 Web Service 客户端,它的目的就是让 Web Service 调用更加简单.它整合了 Ribbon 和 Hystrix,从而让我们不再需要显式地使用这两个组件.F ...
- Introducing ASLR for FreeBSD
Shawn WebbOliver Pinter10 July 2014http://www.hardenedbsd.org/ [ 1. Introduction ]Security in FreeBS ...
- CentOS-6.4-minimal版中安装JDK_Maven_Subversion以及改动rpm包安装路径
完整版见https://jadyer.github.io/2013/09/07/centos-config-develop/ /** * @see -------------------------- ...
- iOS使用push隐藏子页面底部bottom TabBar
下面两种情况是我在开发过程中遇到的,一种是代码使用pushViewController,还有一种是storyboard直接使用push.之前也查阅了非常多关于隐藏底部tabbar的资料.可是要么使用起 ...
- OpenCASCADE Extended Data Exchange - XDE
OpenCASCADE Extended Data Exchange - XDE eryar@163.com Abstract. OpenCASCADE Data Exchange allows de ...
- POJ2823 Sliding Window【双端队列】
求连续的k个中最大最小值,k是滑动的,每次滑动一个 用双端队列维护可能的答案值 假设要求最小值,则维护一个单调递增的序列 对一開始的前k个,新增加的假设比队尾的小.则弹出队尾的,直到新增加的比队尾大. ...