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;}

posted @ 2017-10-08 11:51  PIPIBoss  阅读(199)  评论(0编辑  收藏  举报