西安多校集训-字符串

前言

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;
}
posted @ 2025-03-31 20:36  Tighnari  阅读(7)  评论(0)    收藏  举报