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\n",ans[i]);
printf("%d",app[1]);for(int i=2;i<=n;i++)printf(" %d",app[i]);
}
int main(){work();return 0;}