这个题我使用官方的给的做法,nlogn的时间复杂度,结果Java没过,最后一个样例tle了,即使我用了快读与快输也无济于事,换成c加加就过了,怀疑这个题数据卡的及其严格。差评,差评。实测后,发现有人使用Java运用Manacher算法过了,博主还不会。
流汗流汗,现在挖个坑,先使用字符串hash来解决问题,以后学会了Manacher再来填坑。
言归正传,此题我们要求最大回文子串,我们知道枚举的话至少时n的平方的复杂度,肯定不行。于是我们来优化优化,首先我们可以使用字符串hash来极大降低我们判断回文串的时间。具体做法是,我们首先来枚举最长回文子串的中心位置。我们知道回文子串分为奇数回文子串和偶数回文子串。我们枚举奇数回文子串的中心字符,对于偶数回文子串我们枚举最中心的两个字符里靠后的那一个,当然枚举最中心的两个字符里靠前的那一个也可以。然后,我们来二分答案。怎么来二分呢。我们在预先处理完字符串的hash后,我们将1视为第一个字符的位置。我们以奇数子串为例。我们的循环从1开始,直到n。假设当前位置为m。我们从m-1与n-m这两个数字中选取最小值作为我们针对m位置二分的右端点。左端点设为0.我们知道奇数回文子串,他的中心字符前面有m-1个字符,后面有n-m个字符,既然回文,当然中心字符前面的字符数量要等于后面的,所以我们要选取最小的。接下来二分。我们针对m位置二分mid,mid就是中心字符除外的中心字符往左的所有字符长度,所以左边是m-1到m-mid,右边同理m+1到m+mid。我们对这两个位置的字符求hash值来比较二分出答案后,我们乘以2加1就是选出最长就是奇数答案
针对偶数回文子串。我们从m-1到n-m+1中取得最小值来作为我们二分的右端点,左端点选为0.
同奇数子串的步骤我们在m-mid到m-1和m到m+mid-1来求解。得到二分答案后乘以2,在所有答案中选取最长的,同奇数子串做对比,取最大的作为答案。
再求字符串hash时,我们可以再开一个后缀和,来判断右边字符串的hash值。
上代码
import java.awt.FontFormatException;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.lang.reflect.AnnotatedWildcardType;
import java.math.BigInteger;
import java.sql.SQLIntegrityConstraintViolationException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.Map;
import java.util.PriorityQueue;
import java.util.Scanner;
import java.util.Spliterator.OfPrimitive;
import java.util.function.IntToDoubleFunction;
import java.util.function.LongBinaryOperator;
import java.util.TreeMap;
import java.util.TreeSet;
import javax.management.relation.InvalidRelationTypeException;
import javax.print.attribute.standard.JobMessageFromOperator;
import javax.print.attribute.standard.JobPriority;
import javax.swing.table.TableModel;
import javax.swing.text.TabSet;
public class Main {
public static void main(String[] args) throws IOException {
Scanner sc=new Scanner(System.in);
BufferedReader br1=new BufferedReader(new InputStreamReader(System.in));
PrintWriter pw1=new PrintWriter(System.out);
yuchuyi();
int a=0;
while(true) {
a++;
String a1=br1.readLine();
long answwer=0;
if(a1.equals("END")) {
break;
}
hashchuli(a1);
hash2chuli(a1);
int b=0;
int c=a1.length();
for(b=1;b<=c;b++) {
int d=0;
int e=Math.min(b-1, c-b);
int f=0;
while(d<=e) {
int mid=(d+e)>>>1;
long a2=jisuanhash(b-mid,b-1);
long b2=jisuanhash2(b+1, b+mid);
/* if(b==7) {
System.out.println(a2+" "+b2);
}*/
if(a2==b2) {
f=Math.max(f, mid);
d=mid+1;
}
else {
e=mid-1;
}
}
long jishu=2*f+1;
d=0;
e=Math.min(b-1, c-b+1);
f=0;
while(d<=e){
int mid=(d+e)>>>1;
long a4=jisuanhash(b-mid, b-1);
long b4=jisuanhash2(b, b+mid-1);
/*if(b==10) {
System.out.println("EEE"+a4+" "+b4+" "+mid);
}*/
if(b4==a4) {
f=Math.max(f, mid);
d=mid+1;
}
else {
e=mid-1;
}
}
long oushu=2*f;
long cccc=Math.max(oushu, jishu);
answwer=Math.max(answwer, cccc);
}
pw1.println("Case "+a+":"+" "+answwer);
}
pw1.flush();
pw1.close();
}
public static int aa=(int)(2e6+10);
public static long bb=131;
public static long cc=998244353;
public static long[] hash=new long[aa];
public static long[] hash2=new long[aa];
public static long[] jinzhi=new long[aa];
public static String ddString;
public static long jisuanhash2(int a,int b) {
long c=0;
c=((hash2[a]-hash2[b+1]*jinzhi[b-a+1])%cc+cc)%cc;
return c;
}
public static long jisuanhash(int a,int b) {
long c=0;
c=((hash[b]-hash[a-1]*jinzhi[b-a+1])%cc+cc)%cc;
return c;
}
public static void yuchuyi() {
jinzhi[0]=1;
int a=0;
for(a=1;a<(1e6+67);a++) {
jinzhi[a]=jinzhi[a-1]*bb%cc;
}
}
public static void hashchuli(String aString) {
int a=aString.length();
int b=0;
hash[0]=0;
for(b=1;b<=a;b++) {
hash[b]=(hash[b-1]*bb+aString.charAt(b-1)-'a'+1)%cc;
}
}
public static void hash2chuli(String aString) {
int a=aString.length();
int b=0;
hash2[a+1]=0;
for(b=a;b>=1;b--) {
hash2[b]=(hash2[b+1]*bb+(aString.charAt(b-1)-'a'+1))%cc;
}
}
}