题目:字符串计数
思路:数位dp+hash匹配前后缀
参考题目:https://leetcode.cn/problems/find-all-good-strings/
代码如下:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
import java.util.Set;
public class Main {
//快速输入
static BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
//快速输出
static PrintWriter pw=new PrintWriter(new OutputStreamWriter(System.out));
static int mod=1_000_000_007;
//记录构造到下标i,当前字符串后缀与a前缀最大匹配长度为j的值
static long[][] dp;
//用来记录a的前缀哈希值
static Set<Integer> st;
//记录长度为m的字符串的后缀与a的前缀的最大匹配长度
static Map<String, Integer> map;
//记录p^i,方便哈希值计算
static int[] h;
static int p=31;
//记录当前构造了的字符串
static StringBuilder sb;
public static void main(String[] args) throws IOException {
String s=br.readLine();
int n=Integer.parseInt(s);
s=br.readLine();
char[] c=s.toCharArray();
int m=s.length();
dp=new long[n][m];
st=new HashSet<Integer>();
map=new HashMap<String, Integer>();
h=new int[m];
for(int i=0;i<n;i++) {
Arrays.fill(dp[i], -1);
}
int pre=0;
h[0]=1;
for(int i=0;i<m;i++) {
pre=pre*p+c[i]-'A'+1;
st.add(pre);
if(i>0) {
h[i]=h[i-1]*p;
}
}
sb=new StringBuilder("");
long ans=0;
for(int i=0;i<26;i++) {
sb.append((char)(i+'A'));
int id=compare();
if(id!=m) {
ans=(ans+dfs(1,('A'+i==c[0]?1:0),n,m,c))%mod;
}
sb.deleteCharAt(0);
}
long res=(pow(26,n)-ans+mod)%mod;
pw.println(res);
pw.flush();
}
//快速幂
private static long pow(int x, int n) {
if(n==0) {
return 1;
}
long tmp=pow(x,n/2);
if(n%2==0) {
return tmp*tmp%mod;
}
return tmp*tmp%mod*x%mod;
}
//构造字符串,a表示当前构造的下标,b表示当前字符串的后缀与a的前缀的最大匹配长度,n表示题目要求字符串的长度,m是输入的字符串a的长度,c是输入的字符串
private static long dfs(int a, int b, int n, int m, char[] c) {
if(a==n) {
return 1;
}
if(dp[a][b]!=-1) {
return dp[a][b];
}
long ans=0;
for(int i=0;i<26;i++) {
sb.append((char)(i+'A'));
int id=compare();
if(id!=m) {
ans=(ans+dfs(a+1,id,n,m,c))%mod;
}
sb.deleteCharAt(sb.length()-1);
}
dp[a][b]=ans;
return ans;
}
//比较当前字符串后缀与a的前缀的最大匹配长度
private static int compare() {
String s=sb.toString();
int m=h.length;
if(s.length()>m) {
s=s.substring(s.length()-m);
}
if(map.containsKey(s)) {
return map.get(s);
}
char[] ch=s.toCharArray();
int n=ch.length;
int hash=0;
int ans=0;
for(int i=n-1;i>=0;i--) {
hash+=(ch[i]-'A'+1)*h[n-1-i];
if(st.contains(hash)) {
ans=n-i;
}
}
map.put(s, ans);
return ans;
}
}
受益匪浅,大佬强!