原题链接
首先看T的后缀匹配S的前缀,S的前缀匹配T的后缀这个条件。
实际就是kmp的next的定义。求S+T的ne数组,res1=ne[n+m],然后res1递归代入ne数组直到小于min(n,m)就是T的后缀匹配S的前缀的最大匹配长度。反之同理。
还要保证回文。先看T后缀匹配S前缀的情况:要先求出S最大的回文前缀(直接用S+T的前后缀比较即可)len1。由于题目要求前后缀不相交所以len1求完之后和n-1取min。然后再把res1递归代入ne数组直到小于len1,此时res1就是T后缀匹配S前缀,且都是回文串的最大长度。然后同理求S后缀匹配T前缀,但是len2需要和min(n,m)-res1取min。
求的过程中如果res1,res2其中有一个为0就代表无解。有解则答案为2*(res1+res2)。
但是还没有结束,上述流程优先选择S的前缀,让其尽量大。如果最终选法S的前后缀不相交,则答案没错。若优先考虑S的后缀,该后缀与上述前缀相交,则S的前缀只能是长度小于min(n,m)-res2的匹配T后缀的最大回文前缀,这可能产生更优解。其次,若都不选最大的也可能产生最优解。
所以在求res1时,我们求出所有可选的前缀,当res1<len时,继续把res1代入ne数组,存下所有的res1,并从小到大排序。
求res2时,从小到大遍历所有的res1,求出min(n,m)-res1限制下的最大长度。当第一次求得res2有解时,即可break。
时间复杂度O(n);
发现优先考虑前缀得到ans1,和优先考虑后缀得到ans2,两个取max,也能ac。不知道是有什么性质没发现,还是数据弱了。
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<int,int>;
using pll = pair<ll,ll>;
int n,m;
string S,T;
vector<int> nes,net;
void kmp(string s,vector<int> &ne){
s = ' '+s;
ne[0] = 0;
for(int i=2,j=0;i<=n+m;i++){
while(j && s[i]!=s[j+1]) j = ne[j];
if(s[i]==s[j+1]) j++;
ne[i] = j;
}
return;
}
void solve(){
cin>>n>>m;
cin>>S>>T;
auto calc = [&](string s,string t)->int{
nes.assign(n+m+2,0),net.assign(n+m+2,0);
kmp(s+t,nes);
kmp(t+s,net);
string st = ' '+s+t;
int minl = min(n,m);
int res1 = nes[n+m],len = 0;
for(int i=1;i<=n;i++){
if(st[i]==st[n+m-i+1]) len++;
else break;
}
len = min(len,minl - 1);
while(res1 && res1 > len) res1 = nes[res1];
if(res1==0) return -1;
vector<int> state;
while(res1){
state.push_back(res1);
res1 = nes[res1];
}
sort(state.begin(),state.end());
st = ' '+t+s;
len = 0;
for(int i=1;i<=n;i++){
if(st[i]==st[n+m-i+1]) len++;
else break;
}
int ans = -1;
int res2 = net[n+m];
for(auto v:state){
len = min(len,minl-v);
while(res2 && res2 > len) res2 = net[res2];
if(res2==0) break;
ans = max(ans,2*(v+res2));
}
return ans;
};
int ans1 = calc(S,T);
cout<<ans1<<endl;
}
int main(){
std::ios::sync_with_stdio(0);
std::cout.tie(0);
std::cin.tie(0);
int T = 1;
//cin>>T;
while(T--){
solve();
}
return 0;
}