2754: [SCOI2012]喵星球上的点名
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
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
【提示】
事实上样例给出的数据如果翻译成地球上的语言可以这样来看
2 3
izayoi sakuya
orihara izaya
izay
hara
raiz
HINT
【数据范围】
对于30%的数据,保证:
1<=N,M<=1000,喵星人的名字总长不超过4000,点名串的总长不超过2000。
对于100%的数据,保证:
1<=N<=20000,1<=M<=50000,喵星人的名字总长和点名串的总长分别不超过100000,保证喵星人的字符串中作为字符存在的数不超过10000。
和3172有点类似,也是用AC自动机建立fail树然后在fail树上统计答案。。。
1 #include<iostream> 2 #include<cstdlib> 3 #include<cmath> 4 #include<cstring> 5 #include<cstdio> 6 #include<algorithm> 7 #include<string> 8 #include<map> 9 #include<queue> 10 #include<vector> 11 #include<set> 12 #define inf 1000000000 13 #define maxn 100000+5 14 #define maxm 50000+5 15 #define eps 1e-10 16 #define ll long long 17 #define for0(i,n) for(int i=0;i<(n);i++) 18 #define for1(i,n) for(int i=1;i<=(n);i++) 19 #define for2(i,x,y) for(int i=(x);i<=(y);i++) 20 #define for3(i,x,y) for(int i=(x);i>=(y);i--) 21 #define for4(i,x) for(int i=head[x],y=e[i].go;i;i=e[i].next,y=e[i].go) 22 using namespace std; 23 int read(){ 24 int x=0,f=1;char ch=getchar(); 25 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 26 while(ch>='0'&&ch<='9'){x=10*x+ch-'0';ch=getchar();} 27 return x*f; 28 } 29 int n,m,ans1[maxn],ans2[maxn]; 30 vector<int> a[20005],st[maxn],V,M; 31 map<int,int> next[maxn]; 32 bool v[maxn],mark[maxm]; 33 struct acm{ 34 int tot,ans; 35 int fail[maxn],q[maxn]; 36 acm(){ 37 tot=1; 38 for(int i=-1;i<=10000;i++) 39 next[0][i]=1; 40 fail[1]=0; 41 } 42 void insert(int pos){ 43 int now=1,L=read(); 44 for1(i,L){ 45 int x=read(); 46 if(!next[now][x])next[now][x]=++tot; 47 now=next[now][x]; 48 } 49 st[now].push_back(pos); 50 } 51 void build(){ 52 int head=0,tail=1; 53 q[0]=1; 54 while(head!=tail){ 55 int now=q[head];head++; 56 for(map<int,int>::iterator i=next[now].begin();i!=next[now].end();i++){ 57 int t=i->first,k=fail[now]; 58 while(!next[k][t])k=fail[k]; 59 fail[i->second]=next[k][t]; 60 q[tail++]=i->second; 61 } 62 } 63 } 64 void get(int pos,int x){ 65 for(int i=x;i;i=fail[i]) 66 if(!v[i]){ 67 v[i]=1;V.push_back(i); 68 for(int j=0;j<st[i].size();j++) 69 if(!mark[st[i][j]]){ 70 mark[st[i][j]]=1;M.push_back(st[i][j]); 71 ans1[st[i][j]]++; 72 ans2[pos]++; 73 } 74 } 75 else break; 76 } 77 void solve(int x){ 78 int now=1; 79 for0(i,a[x].size()){ 80 int t=a[x][i]; 81 while(!next[now][t])now=fail[now]; 82 now=next[now][t];get(x,now); 83 } 84 for0(i,V.size())v[V[i]]=0; 85 for0(i,M.size())mark[M[i]]=0; 86 V.clear();M.clear(); 87 } 88 }acm; 89 int main(){ 90 //freopen("input.txt","r",stdin); 91 //freopen("output.txt","w",stdout); 92 n=read();m=read(); 93 int L,x; 94 for1(i,n){ 95 L=read(),x; 96 while(L--)x=read(),a[i].push_back(x); 97 a[i].push_back(-1); 98 L=read(); 99 while(L--)x=read(),a[i].push_back(x); 100 } 101 for1(i,m) 102 acm.insert(i); 103 acm.build(); 104 for1(i,n) 105 acm.solve(i); 106 for1(i,m)printf("%d\n",ans1[i]); 107 for1(i,n){ 108 printf("%d",ans2[i]); 109 if(i!=n)printf(" "); 110 } 111 return 0; 112 }