传送门:Easygoing Single Tune Circulation

题意

给定n个字符串 s[i],再给出m个查询的字符串 t[i],问 t[i] 是否为某个 s[i] 循环无限次的子串。

题解

分成两种情况

① t[i] 比 s[j] 短, 这个时候可以用后缀自动机,把每个 s[j] 重复一次,然后放到SAM中,这样直接每次直接查询就好了。当然,因为是有t(t<=1e5)组数据,全部初始化肯定会超时的,所以下一个要用到哪部分哪部分就初始化,这样最多初始化1e6次,因为所有的长度不会超过1e6。

② t[i] 比 s[j] 长,这样的话就不能用后缀自动机了,因为并不知道 t[i] 到底是 s[j] 重复了几次的子串。考虑到 t[i] 如果是某个 s[j] 循环无限次的子串,那么他一定是有循环节的,因为不知道有没有循环节,所以找到第一个最长的且每个字母只出现了一次的子串,并用最小表示法表示,然后在一颗插入了每个 s[j] 的最小表示法的字典树中查找是否有这个子串,如果有的话,构造长度为 |t[i]|,以该子串为循环节的串,如果这个串就是 t[i] 那么说明有该串,否则没有。当然,字典树的初始化也会卡,所以同样的边用边初始化下一个即将要用的。

代码

  1 #include<bits/stdc++.h>
2 using namespace std;
3
4 const int maxn=1e6+10;
5
6 struct SAM
7 {
8 int mxlen[maxn<<1],link[maxn<<1],nt[maxn<<1][26];
9 int sz,last,len;
10 void init()
11 {
12 memset(nt[0],0,sizeof(nt[0]));
13 mxlen[0]=0;
14 link[0]=-1;
15 sz=1;
16 last=0;
17 }
18
19 void extend(int c)
20 {
21 c-='a';
22 int cur=sz++;
23 mxlen[cur]=mxlen[last]+1;
24 int p=last;
25 memset(nt[cur],0,sizeof(nt[cur]));
26 while(p!=-1&&!nt[p][c]){
27 nt[p][c]=cur;
28 p=link[p];
29 }
30 if(p==-1) link[cur]=0;
31 else{
32 int q=nt[p][c];
33 if(mxlen[p]+1==mxlen[q]) link[cur]=q;
34 else{
35 int clone=sz++;
36 mxlen[clone]=mxlen[p]+1;
37 memcpy(nt[clone],nt[q],sizeof(nt[q]));
38 link[clone]=link[q];
39 while(p!=-1&&nt[p][c]==q){
40 nt[p][c]=clone;
41 p=link[p];
42 }
43 link[q]=link[cur]=clone;
44 }
45 }
46 last=cur;
47 }
48 bool query(string s)
49 {
50 int p=0;
51 for(int i=0;i<s.size();i++){
52 int c=s[i]-'a';
53 if(!nt[p][c]) return 0;
54 p=nt[p][c];
55 }
56 return 1;
57 }
58 }sam;
59
60 struct Trie
61 {
62 int tree[maxn][30];
63 int color[maxn];
64 int k=1;
65
66 int newnode()
67 {
68 memset(tree[k],0,sizeof(tree[k]));
69 color[k]=0;
70 return k++;
71 }
72
73 void init()
74 {
75 color[0]=0;
76 memset(tree[0],0,sizeof(tree[0]));
77 k=1;
78 }
79
80 void insert(string a)
81 {
82 int p=0;
83 int len=a.size();
84 for(int i=0;i<len;i++){
85 int c=a[i]-'a';
86 if(!tree[p][c]) {
87 tree[p][c]=newnode();
88 }
89 p=tree[p][c];
90 }
91 color[p]++;
92 }
93 int query(string a)
94 {
95 int p=0;
96 int len=a.size();
97 for(int i=0;i<len;i++){
98 int c=a[i]-'a';
99 if(!tree[p][c]) return 0;
100 p=tree[p][c];
101 }
102 return color[p];
103 }
104 }trie;
105
106 const int maxm=1e5+10;
107 string s[maxm];
108
109 string get_min(string s)
110 {
111 string t;
112 int p=26,pos=0;
113 for(int i=0;i<s.size();i++){
114 if(s[i]-'a'<=p) p=s[i]-'a',pos=i;
115 }
116 t=s.substr(pos);
117 t+=s.substr(0,pos);
118 return t;
119 }
120
121 int main()
122 {
123 ios::sync_with_stdio(false);
124 cin.tie(0);
125 cout.tie(0);
126 int T;
127 cin>>T;
128 int k=1;
129 while(T--){
130 sam.init();
131 trie.init();
132 cout<<"Case #"<<k++<<":"<<endl;
133 int n;
134 cin>>n;
135 for(int i=0;i<n;i++){
136 cin>>s[i];
137 string t=get_min(s[i]);
138 trie.insert(t);
139 }
140 for(int i=0;i<n;i++){
141 sam.last=0;
142 for(int j=0;j<s[i].size();j++) sam.extend(s[i][j]);
143 for(int j=0;j<s[i].size();j++) sam.extend(s[i][j]);
144 }
145 int m;
146 cin>>m;
147 while(m--){
148 string a;
149 cin>>a;
150 if(sam.query(a)){
151 cout<<"YES"<<endl;
152 continue;
153 }
154 int pos=a.size();
155 for(int i=1;i<pos;i++){
156 if(a[i]==a[0]){
157 pos=i;
158 break;
159 }
160 }
161 string t=a.substr(0,pos);
162 string tt=get_min(t);
163 if(trie.query(tt)){
164 string p;
165 for(int i=0;i<a.size();i++){
166 p+=t[i%t.size()];
167 }
168 if(p==a){
169 cout<<"YES"<<endl;
170 continue;
171 }
172 }
173 cout<<"NO"<<endl;
174 }
175 }
176 return 0;
177 }

牛客15334 Easygoing Single Tune Circulation(后缀自动机+字典树)的更多相关文章

  1. BZOJ3413: 匹配(后缀自动机 线段树合并)

    题意 题目链接 Sol 神仙题Orz 后缀自动机 + 线段树合并... 首先可以转化一下模型(想不到qwq):问题可以转化为统计\(B\)中每个前缀在\(A\)中出现的次数.(画一画就出来了) 然后直 ...

  2. cf666E. Forensic Examination(广义后缀自动机 线段树合并)

    题意 题目链接 Sol 神仙题Orz 后缀自动机 + 线段树合并 首先对所有的\(t_i\)建个广义后缀自动机,这样可以得到所有子串信息. 考虑把询问离线,然后把\(S\)拿到自动机上跑,同时维护一下 ...

  3. 洛谷P2178 [NOI2015]品酒大会(后缀自动机 线段树)

    题意 题目链接 Sol 说一个后缀自动机+线段树的无脑做法 首先建出SAM,然后对parent树进行dp,维护最大次大值,最小次小值 显然一个串能更新答案的区间是\([len_{fa_{x}} + 1 ...

  4. BZOJ1396: 识别子串(后缀自动机 线段树)

    题意 题目链接 Sol 后缀自动机+线段树 还是考虑通过每个前缀的后缀更新答案,首先出现次数只有一次,说明只有\(right\)集合大小为\(1\)的状态能对答案产生影响 设其结束位置为\(t\),代 ...

  5. [Luogu5161]WD与数列(后缀数组/后缀自动机+线段树合并)

    https://blog.csdn.net/WAautomaton/article/details/85057257 解法一:后缀数组 显然将原数组差分后答案就是所有不相交不相邻重复子串个数+n*(n ...

  6. 洛谷P4493 [HAOI2018]字串覆盖(后缀自动机+线段树+倍增)

    题面 传送门 题解 字符串就硬是要和数据结构结合在一起么--\(loj\)上\(rk1\)好像码了\(10k\)的样子-- 我们设\(L=r-l+1\) 首先可以发现对于\(T\)串一定是从左到右,能 ...

  7. luogu5212/bzoj2555 substring(后缀自动机+动态树)

    对字符串构建一个后缀自动机. 每次查询的就是在转移边上得到节点的parent树中后缀节点数量. 由于强制在线,可以用动态树维护后缀自动机parent树的子树和. 注意一个玄学的优化:每次在执行连边操作 ...

  8. 模板—字符串—后缀自动机(后缀自动机+线段树合并求right集合)

    模板—字符串—后缀自动机(后缀自动机+线段树合并求right集合) Code: #include <bits/stdc++.h> using namespace std; #define ...

  9. 【BZOJ4556】[TJOI2016&HEOI2016] 字符串(后缀自动机+线段树合并+二分)

    点此看题面 大致题意: 给你一个字符串\(s\),每次问你一个子串\(s[a..b]\)的所有子串和\(s[c..d]\)的最长公共前缀. 二分 首先我们可以发现一个简单性质,即要求最长公共前缀,则我 ...

随机推荐

  1. .NET 云原生架构师训练营(模块二 基础巩固 RabbitMQ Masstransit 介绍)--学习笔记

    2.6.6 RabbitMQ -- Masstransit 介绍 Masstransit 是什么 Quickstart 消息 Message Masstransit 是什么 Masstransit 是 ...

  2. 【C++】《Effective C++》第九章

    杂项讨论 条款53:不要轻忽编译器的警告 请记住 严肃对待编译器发出的警告信息.努力在你的编译器的最高(最严苛)警告级别下争取"无任何警告"的容易. 不要过度依赖编译器的报警能力, ...

  3. Java开发手册之安全规约

    1.用户敏感数据禁止直接展示,必须对展示数据进行脱敏.例如手机号.银行卡号等,中间要用*隐藏. 2.发贴.评论.发送即时消息等用户生成内容的场景必须实现防刷.文本内容违禁词过滤等风控策略,一般是用验证 ...

  4. ctfhub技能树—sql注入—报错注入

    打开靶机 payload 1 Union select count(*),concat((查询语句),0x26,floor(rand(0)*2))x from information_schema.c ...

  5. 通过LOGMNR查找程式带入的实际值

    生产库中出现了大量的锁表,需要得到当时程式执行的SQL以及其带入的值 1.查看SQL SELECT SQL_ID FROM V$SESSION WHERE SID=(SELECT FINAL_BLOC ...

  6. 在Ubuntu18.04下编译出ffmpeg(支持推流H265成rtmp)

    Ubuntu18.04下编译libx264.libx265.libfdk_aac和ffmpeg 一.编译x264库 二.编译fdk-aac库 三.编译x265库 四.编译FFmpeg源码 五.设置环境 ...

  7. Centos7.4 小白式安装(初学)

    虚拟机安装Centos7.4系统 适用人群(初学者) 下载Centos7.4镜像 https://pan.baidu.com/s/1NtjfdHV3OWAvfDj5vrR7HQ  提取码:hzzw 虚 ...

  8. javascript判断浏览器访问,刷新,返回

    话不多说,直接上 if (window.performance.navigation.type === 0/* 正常访问 */) { // 你要干的事 } else if (window.perfor ...

  9. uni-app开发经验分享十: 封装request请求

    http.js //封装requset,uploadFile和downloadFile请求,新增get和post请求方法 let http = { 'setBaseUrl': (url) => ...

  10. 云原生流水线 Argo Workflow 的安装、使用以及个人体验

    注意:这篇文章并不是一篇入门教程,学习 Argo Workflow 请移步官方文档 Argo Documentation Argo Workflow 是一个云原生工作流引擎,专注于编排并行任务.它的特 ...