原文链接https://www.cnblogs.com/zhouzhendong/p/CF109D.html
题目传送门 - CF109D
题意
给定两个字符串 $a,b$ ,求一组 $i,j$ 使得 $f(a,i,j)=b$ 。如果无解输出 "-1 -1" ,如果多组解,输出 i 尽量大的;如果 i 相同,输出 j 尽量小的。
其中 $f(s,i,j) = s[i+1 cdots j-1] + r(s[0 cdots i]) + r(s[jcdots n-1])$ 。 $n$ 为串长。其中 $s[icdots j]$ 表示 串 $s$ 的 $i$ 至 $j$ 个位置构成的子串,+ 运算定义为字符串顺序拼接,$r(s)$ 表示 $s$ 翻转后得到的串。
$|a|,|b| leq 10^6$
题解
那个最大最小问题不大,我们来看看如何找一组解。
首先,讲 a 串翻转。则问题变成了 $r(a[i+1]cdots a[j-1])+a[0cdots i] + a[jcdots n-1]=b$ 的 $(i,j)$ 。这个问题,只需要枚举 $j$ ,然后判定是否可以行即可。
对于 $r(a[i+1]cdots a[j-1])$ 与 $b$ 的最大匹配长度,可以二分 + 哈希。
对于以 b 串第 $j-1$ 个位置结尾的子串中与 $a$ 的前缀的匹配长度最大为多少,直接 KMP 。
如果这两个长度大于 $j-1$ ,那么就可行。
那个什么最大最小的,随便弄一弄就好了。
注意我们求出来的翻转后的 a 串的答案,最后还要变换一下。
代码
#include <bits/stdc++.h> using namespace std; typedef unsigned long long ULL; const int N=1000005*2; char a[N],b[N]; int n,Next[N],len[N]; ULL Ha[N],Hb[N],Fac[N],T=233; ULL Get_Hash(ULL *Ha,int L,int R){ if (L>R) L=n*2-L+1,R=n*2-R+1; return Ha[R]-Ha[L-1]*Fac[R-L+1]; } void KMP(char *a,char *b,int n){ for (int i=2,k=0;i<=n;Next[i]=k+=(a[k+1]==a[i]),i++) while (k>0&&a[k+1]!=a[i]) k=Next[k]; for (int i=1,k=0;i<=n;len[i]=k+=(a[k+1]==b[i]),i++) while (k>0&&a[k+1]!=b[i]) k=Next[k]; } int Get(int j){ int L=1,R=j-1,mid,k1=0; while (L<=R){ mid=(L+R)>>1; if (Get_Hash(Hb,1,mid)==Get_Hash(Ha,j-1,j-mid)) L=mid+1,k1=mid; else R=mid-1; } return k1+len[j-1]<j-1?-1:len[j-1]; } int main(){ gets(a+1),gets(b+1); n=strlen(a+1); if (strlen(b+1)!=n) return puts("-1 -1"),0; reverse(a+1,a+n+1); for (int i=n+1;i<=n*2;i++) a[i]=a[n*2-i+1],b[i]=b[n*2-i+1]; KMP(a,b,n); for (int i=Fac[0]=1;i<=n*2;i++){ Fac[i]=Fac[i-1]*T; Ha[i]=Ha[i-1]*T+a[i]; Hb[i]=Hb[i-1]*T+b[i]; } int ansi=10000000,ansj=10000000,d=-1; for (d=n;d>1;d--) if (a[d]!=b[d]) break; for (int i=-1,j=d+1;j<=n&&!~i;j++) if (~(i=Get(j))) ansi=i,ansj=j; if (ansj==10000000) ansi=ansj=-1; else ansi=n-ansi,ansj=n-ansj; printf("%d %d ",ansj,ansi); return 0; }