题意:给你n个字符串,问你是否存在一个字符串可以从中找到其他n-1个字符串。
思路:其实很简单,找到最长的那个字符串对他进行匹配,看是否能匹配到n-1个字符串。
可以用AC自动机或者后缀自动机做,但是AC自动机用指针的话会MLE,但是我比赛的时候用自己的后缀自动机的板子T了!
然后用了dalao的板子,还是我的板子不够优秀啊(┬_┬)
AC自动机版:
#include<iostream> #include<cstdio> #include<string> #include<cstring> #include<vector> #include<cmath> #include<queue> #include<stack> #include<map> #include<set> #include<algorithm> using namespace std; const int maxn=1e5+100; const int maxm=50*10010; const int SIGMA_SIZE=26; int n; char t[maxn],s[maxn]; struct AC { int ch[maxm][26]; int val[maxm]; int fail[maxm],last[maxm]; int sz; void clear(){memset(ch[0],0,sizeof(ch[0]));sz=1;} int idx(char x){return x-'a';} void insert(char *s) { int u=0; int n=strlen(s); for(int i=0;i<n;i++) { int c=idx(s[i]); if(!ch[u][c]) { memset(ch[sz],0,sizeof(ch[sz])); val[sz]=0; ch[u][c]=sz++; } u=ch[u][c]; } val[u]++; } void getfail() { queue<int> q; fail[0]=0; int u=0; for(int i=0;i<SIGMA_SIZE;i++) { u=ch[0][i]; if(u){q.push(u);fail[u]=0;last[u]=0;} } while(!q.empty()) { int r=q.front();q.pop(); for(int i=0;i<SIGMA_SIZE;i++) { u=ch[r][i]; if(!u){ch[r][i]=ch[fail[r]][i];continue;} q.push(u); int v=fail[r]; while(v&&!ch[v][i])v=fail[v]; fail[u]=ch[v][i]; last[u]=val[fail[u]]?fail[u]:last[fail[u]]; } } } int find(char *s) { int u=0,cnt=0; int n=strlen(s); for(int i=0;i<n;i++) { int c=idx(s[i]); u=ch[u][c]; int temp=0;//必须赋初值为0,表示如果下面两个判断都不成立的时候while可以正常执行 if(val[u]) temp=u; else if(last[u]) temp=last[u]; while(temp) { cnt+=val[temp]; val[temp]=0; temp=last[temp]; } } return cnt; } }tree; string a[maxn]; void solve() { scanf("%d",&n); tree.clear(); int maxx=0, id=0; for(int i=1;i<=n;i++) { scanf("%s",t); tree.insert(t); int len=strlen(t); if (len>maxx) { maxx=len; id=i; } a[i]=string(t); } tree.getfail(); int len=a[id].length(); for (int i=0; i<len; i++) t[i]=a[id][i]; int ans=tree.find(t); //printf("%d\n",ans); if (ans==n) puts(t); else puts("No"); } int main() { int t = 1; //freopen("in.txt", "r", stdin); //freopen("out.txt", "w", stdout); scanf("%d", &t); while(t--) solve(); return 0; }
后缀自动机:
/** @xigua */ #include <stdio.h> #include <cmath> #include <iostream> #include <algorithm> #include <vector> #include <stack> #include <cstring> #include <queue> #include <set> #include <string> #include <map> #include <climits> #define PI acos(-1) #define rep(a,b,c) for(int (a)=(b); (a)<(c); ++(a)) #define drep(a,b,c) for(int (a)=(b); (a)>(c); --(a)) #define CLR(x) memset(x, 0, sizeof(x)) #define sf scanf #define pf printf using namespace std; typedef long long ll; typedef double db; const int maxn = 1e5 + 1000; const int ma = 1e5 + 1000; const int mod = 1e9 + 7; const int INF = 1e8 + 5; const ll inf = 1e17 + 5; const db eps = 1e-6; const int MAXN = 2e5+1e3; char pool[MAXN]; struct Str{ int st, len; }str[MAXN]; struct state { int len, pre, ch[26]; }; struct SAM { int sz, last; state st[MAXN]; state& operator[] (int x) { return st[x]; } void clear(int x) { CLR(st[x].ch); } void init() { sz=1, last=0; st[0].len=0, st[0].pre=-1; clear(0); } void add(int c) { int cur=sz++, p; clear(cur); st[cur].len=st[last].len+1; for(p=last; p!=-1&&!st[p].ch[c]; p=st[p].pre) st[p].ch[c]=cur; if(p==-1) st[cur].pre=0; else { int q=st[p].ch[c]; if(st[q].len==st[p].len+1) st[cur].pre=q; else { int clone=sz++; st[clone]=st[q]; st[clone].len=st[p].len+1; st[cur].pre=st[q].pre=clone; for(; p!=-1&&st[p].ch[c]==q; p=st[p].pre) st[p].ch[c]=clone; } } last=cur; } int find(string t) {//查询lcs int now=0, l=0, ans=0; int len=t.length(); for (int i=0; i<len; i++) { while(now&&!st[now].ch[t[i]-'a']) { now=st[now].pre; l=st[now].len; } if(st[now].ch[t[i]-'a']) { ++l; now=st[now].ch[t[i]-'a']; } ans=max(l, ans); } return ans; } } sam; string a[maxn]; bool check(int sel, int n) { for (int i=0; i<n; i++) { if (i!=sel) { if (sam.find(a[i])!=a[i].length()) return 0; } } return true; } char ans[maxn]; void solve() { int n; scanf("%d", &n); str[0].st=0; int sel=0, maxx=0; for (int i=0; i<n; i++) { scanf("%s", pool); int len=strlen(pool); if (len>maxx) { maxx=len; sel=i; } a[i]=string(pool); } sam.init(); int len=a[sel].length(); for (int i=0; i<len; i++) sam.add(a[sel][i]-'a'); for (int i=0; i<len; i++) ans[i]=a[sel][i]; if(check(sel,n)) { int l=a[sel].length(); for (int i=0; i<len; i++) printf("%c", ans[i]); puts(""); } else puts("No"); } int main() { int t = 1, cas = 1; //freopen("in.txt", "r", stdin); // freopen("out.txt", "w", stdout); scanf("%d", &t); while(t--) { // printf("Case %d: ", cas++); solve(); } return 0; }