西安多校集训-字符串
前言
fun fact: 在 c层 听的,下午刚上课比较困,回神来发现讲的听不懂了,光速打开 OiWiki 看了二十分钟,在一听还没我看的快。
AC自动机
建立 Trie 树之后,关键是搭建失配指针,大致的还是上 OiWiki 或者别的大佬的博客吧,我写不出来。
板子1
#include<iostream>
#include<queue>
using namespace std;
const int N=1e6+50;
struct Tree{
int fail;
int vis[30];
int end;
}tr[N];
int tot;
void insert(string s){
int u=0;
for(int i=0;i<(int)s.length();i++){
if(tr[u].vis[s[i]-'a']==0){
tr[u].vis[s[i]-'a']=++tot;
}
u=tr[u].vis[s[i]-'a'];
}
tr[u].end+=1;
return ;
}
void build_fail(){
queue<int> que;
for(int i=0;i<26;i++){
if(tr[0].vis[i]!=0){
tr[tr[0].vis[i]].fail=0;
que.push(tr[0].vis[i]);
}
}
while(!que.empty()){
int u=que.front();
que.pop();
for(int i=0;i<26;i++){
if(tr[u].vis[i]!=0){
tr[tr[u].vis[i]].fail=tr[tr[u].fail].vis[i];
que.push(tr[u].vis[i]);
}else{
tr[u].vis[i]=tr[tr[u].fail].vis[i];
}
}
}
}
int query(string s){
int len=s.length()-1;
int u=0,ans=0;
for(int i=0;i<=len;i++){
u=tr[u].vis[s[i]-'a'];
for(int t=u;t&&tr[t].end!=-1;t=tr[t].fail){
ans+=tr[t].end;
tr[t].end=-1;
}
}
return ans;
}
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++){
string s;
cin>>s;
insert(s);
}
tr[0].fail=0;
build_fail();
string s;
cin>>s;
cout<<query(s);
return 0;
}
板子2
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
const int N=1e6+50;
struct Tree{
int fail;
int vis[30];
int en;
}tr[N];
int tot;
int n;
struct Q{
int num,pos;
}q[N];
bool cmp(Q a,Q b){
if(a.num==b.num) return a.pos<b.pos;
return a.num>b.num;
}
string s[N];
void init(int x){
tr[x].fail=tr[x].en=0;
memset(tr[x].vis,0,sizeof(tr[x].vis));
return ;
}
void insert(string s,int num){
int u=0;
for(int i=0;i<(int)s.length();i++){
if(tr[u].vis[s[i]-'a']==0){
tr[u].vis[s[i]-'a']=++tot;
init(tot);
}
u=tr[u].vis[s[i]-'a'];
}
tr[u].en=num;
return ;
}
void build_fail(){
queue<int> que;
for(int i=0;i<26;i++){
if(tr[0].vis[i]!=0){
tr[tr[0].vis[i]].fail=0;
que.push(tr[0].vis[i]);
}
}
while(!que.empty()){
int u=que.front();
que.pop();
for(int i=0;i<26;i++){
if(tr[u].vis[i]!=0){
tr[tr[u].vis[i]].fail=tr[tr[u].fail].vis[i];
que.push(tr[u].vis[i]);
}else{
tr[u].vis[i]=tr[tr[u].fail].vis[i];
}
}
}
}
int query(string s){
int u=0,res=0;
for(int i=0;i<(int)s.length();i++){
u=tr[u].vis[s[i]-'a'];
for(int t=u;t;t=tr[t].fail){
q[tr[t].en].num++;
}
}
return res;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
while(cin>>n){
if(n==0) break;
tot=0;
init(0);
for(int i=1;i<=n;i++){
cin>>s[i];
q[i].num=0;
q[i].pos=i;
insert(s[i],i);
}
tr[0].fail=0;
build_fail();
cin>>s[0];
query(s[0]);
sort(q+1,q+1+n,cmp);
cout<<q[1].num<<'\n';
cout<<s[q[1].pos]<<'\n';
for(int i=2;i<=n;i++){
if(q[i].num==q[i-1].num)
cout<<s[q[i].pos]<<'\n';
else
break;
}
}
return 0;
}
manacher马拉车
为了防止讨论奇偶回文串的问题,在原序列每个字符中加入 '#' 然后就是只存在寄回文串了,而且也不影响原回文串,具体操作就是暴力扩展了。
#include<iostream>
#include<cstring>
using namespace std;
const int N=2e7+2e6+50;
char s[N];
int cnt;
int pos[N];
int ans=0;
void read(){
char c=getchar();
s[0]='!';
s[++cnt]='#';
while(c<'a' || c>'z') c=getchar();
while(c>='a' && c<='z'){
s[++cnt]=c;
s[++cnt]='#';
c=getchar();
}
return ;
}
int main(){
read();
for(int i=1,r=0,mid=0;i<=cnt;i++){
if(i<=r) pos[i]=min(pos[mid*2-i],r-i+1);
while(s[i-pos[i]]==s[i+pos[i]]) ++pos[i];
if(pos[i]+i>r) r=pos[i]+i-1,mid=i;
if(pos[i]>ans) ans=pos[i];
}
cout<<ans-1;
return 0;
}