21.6.1 t1
6.1还在考试的屑
tag:SAM,PAM
最终的回文串一定由这样的形式组成:
- \(s1+s2+s3\)
其中 \(s1\) 为 \(a\) 串子串,\(s3\) 为 \(b\) 串子串,且 \(s1=rev(s3)\)。
\(s2\) 为一个回文串(可以是 \(a\) 的子串也可以是 \(b\) 的子串)
\(s2\) 可以看作是求以一个位置为左/右端点的最长回文字串,可以 \(PAM\) 解决 \(O(n)\)
\(s1,s3\) 可以用SAM求出。往广义SAM里分别插入 \(a\) 和 \(rev(b)\),枚举 \(s1\) 的右端点 \(i\),然后答案就是 \(\max(len(lca(posa_i,posb_j)))+(\)以\(i+1\)为左端点的最长回文子串\()\)。
然后你会发现那个 \(\max\) 一定是取dfs序上最接近 \(posa_i\) 的两个点。
(很显然这是个十分繁琐的做法)
所以理论复杂度是 \(O(n)\)(这里的lca可以离线),但是由于常数过大导致 \(8e5\) 本地跑了 \(3.5s\),得分 \(70\)。(其中建SAM用时\(1.5s\),建PAM用时\(0.06s\))
不知道是否有更优秀的做法。
update:标算是对一个串建SAM然后用另一个串跑匹配,应该是常数更优秀
根据标算改的代码,最大点247ms
#include<bits/stdc++.h>
using namespace std;
template<typename T>
inline void Read(T &n){
char ch; bool flag=false;
while(!isdigit(ch=getchar()))if(ch=='-')flag=true;
for(n=ch^48;isdigit(ch=getchar());n=(n<<1)+(n<<3)+(ch^48));
if(flag)n=-n;
}
enum{
MAXN = 800005
};
namespace PAM{
char s[MAXN];
struct node{
int son[26], fa, len;
#define son(x,opt) t[x].son[opt]
#define fa(x) t[x].fa
#define len(x) t[x].len
}t[MAXN];
int node_cnt;
inline int Find(int x, int r){
while(s[r-len(x)-1]!=s[r]) x = fa(x);
return x;
}
int prv;
inline int insert(int r){
prv = Find(prv,r); int now = son(prv,s[r]-'a');
if(!now){
now = ++node_cnt;
len(now) = len(prv)+2;
fa(now) = son(Find(fa(prv),r),s[r]-'a');
son(prv,s[r]-'a') = now;
}
return prv=now;
}
inline void clear(){
for(register int i=0; i<=node_cnt; i++) fa(node_cnt) = len(node_cnt) = 0, memset(t[i].son,0,sizeof t[i].son);
node_cnt = prv = 1;
len(1) = -1; fa(0) = 1; fa(1) = 1;
}
}
struct node{int son[26], fa, len;}t[MAXN<<1];
int node_cnt, prv;
inline int insert(char v){
int x = ++node_cnt; len(x) = len(prv)+1;
while(prv and !son(prv,v)) son(prv,v) = x, prv = fa(prv);
if(!prv) fa(x) = 1;
else{
int p = son(prv,v);
if(len(p) == len(prv)+1) fa(x) = p;
else{
int new_p = ++node_cnt; len(new_p) = len(prv)+1;
fa(new_p) = fa(p); fa(p) = fa(x) = new_p;
copy(t[p].son,t[p].son+26,t[new_p].son);
while(prv and son(prv,v)==p) son(prv,v) = new_p, prv = fa(prv);
}
}
return prv=x;
}
inline void clear(){
PAM::clear();
for(register int i=1; i<=node_cnt; i++) len(i) = fa(i) = 0, memset(t[i].son,0,sizeof t[i].son);
node_cnt = prv = 1;
}
int n, ans;
int f[MAXN];
inline void solve(char *a, char *b){
// printf("solve %s %s\n",a+1,b+1);
clear();
for(register int i=1; i<=n; i++) PAM::s[i] = a[n-i+1];
for(register int i=1; i<=n; i++) f[n-i+1] = PAM::len(PAM::insert(i)); f[n+1] = 0;
for(register int i=n; i>=1; i--) insert(b[i]-'a');
int cur=1, nowlen=0;
for(register int i=1; i<=n; i++){
char v = a[i]-'a';
while(cur and !son(cur,v)) cur = fa(cur), nowlen = min(nowlen,len(cur));
if(!cur) cur = 1;
else cur = son(cur,v), nowlen++, ans = max(ans,nowlen*2+f[i+1]);
}
// printf("ans=%d\n",ans);
}
char a[MAXN], b[MAXN];
int main(){
// freopen("1.in","r",stdin);
int T; Read(T);
while(T--){
scanf("%s%s",a+1,b+1);
n = strlen(a+1); ans = -1;
solve(a,b);
for(register int i=1; i<n-i+1; i++) swap(a[i],a[n-i+1]), swap(b[i],b[n-i+1]);
solve(b,a);
cout<<ans<<'\n';
}
return 0;
}

浙公网安备 33010602011771号