BZOJ2754 SCOI2012喵星球上的点名

绝世好题。

正当我犹豫不决时,hzwer说:“MAP!!!”

没错这题大大的暴力,生猛的stl,贼基尔爽,,ԾㅂԾ,,

由于我们求点名在名字中的子串个数,所以将点名建AC自动机,记录节点属于哪次点名,每次带着这位同学的所有名字去里面扫,注意判重

复杂度20000*100000以及玄学的stl复杂度。

By:大奕哥

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N=1e5+10;
 4 int ans1[N],ans2[N],fail[N],n,m,cnt;
 5 map<int,int>t[N];
 6 vector<int>pos[N],a[N];
 7 queue<int>q;
 8 void build(int id)
 9 {
10     int x,k;scanf("%d",&x);int now=0;
11     for(int i=1;i<=x;++i)
12     {
13         scanf("%d",&k);
14         if(!t[now][k])t[now][k]=++cnt;
15         now=t[now][k];
16     }
17     pos[now].push_back(id);
18 }
19 void getfail()
20 {
21     for(map<int,int>::iterator i=t[0].begin();i!=t[0].end();++i)
22     {
23         int u=i->second;
24         q.push(u);
25         fail[u]=0;
26     }
27     while(!q.empty())
28     {
29         int x=q.front();q.pop();
30         for(map<int,int>::iterator i=t[x].begin();i!=t[x].end();++i)
31         {
32             int c=i->first,u=i->second;
33             q.push(u);
34             int k=fail[x];
35             while(k&&!t[k][c])k=fail[k];
36             fail[u]=t[k][c];
37         }
38     }
39 }
40 bool v[N],mark[N];
41 vector<int>H,M;
42 void get(int x,int p)
43 {
44     for(int i=p;i;i=fail[i])
45     {
46         if(v[i])return;
47         v[i]=1;H.push_back(i);
48         for(int j=0;j<pos[i].size();++j)
49         if(!mark[pos[i][j]])
50         {
51             mark[pos[i][j]]=1;
52             ans1[pos[i][j]]++;
53             ans2[x]++;
54             M.push_back(pos[i][j]);
55         }
56     }
57     return;
58 }
59 void find(int x,vector<int>g)
60 {
61     int ans=0,now=0,l=g.size();
62     for(int i=0;i<l;++i)
63     {
64         int c=g[i];
65         while(now&&!t[now][c])now=fail[now];
66         now=t[now][c];
67         get(x,now);
68     }
69     for(int i=0;i<H.size();++i)v[H[i]]=0;
70     for(int i=0;i<M.size();++i)mark[M[i]]=0;
71     H.clear();M.clear();
72     return;
73 }
74 int main()
75 {
76     scanf("%d%d",&n,&m);int x,k;
77     for(int i=1;i<=n;++i)
78     {
79         scanf("%d",&x);
80         for(int j=1;j<=x;++j)
81         scanf("%d",&k),a[i].push_back(k);
82         a[i].push_back(-1);//添加非法字符防止姓和名连在一起成一个子串
83         scanf("%d",&x);
84         for(int j=1;j<=x;++j)
85         scanf("%d",&k),a[i].push_back(k);
86     }
87     for(int i=1;i<=m;++i)build(i);
88     getfail();
89     for(int i=1;i<=n;++i)
90     find(i,a[i]);
91     for(int i=1;i<=m;++i)printf("%d\n",ans1[i]);
92     for(int i=1;i<n;++i)printf("%d ",ans2[i]);
93     printf("%d",ans2[n]);
94     return 0;
95 }

 

转载于:https://www.cnblogs.com/nbwzyzngyl/p/8330171.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值