import java.util.*;
public class Main{
public static void main(String[] args){
String S = "yasherhs";
String[] words = {"say","she","shr","he","her","hs"};
System.out.println(numMatchingSubseq(S,words));
}
public static int numMatchingSubseq(String S, String[] words) {
int len = words.length;
Node root = new Node(0);
for(int i=0;i<len;i++){
insert(root,words[i]);
}
adjustFail(root);
char[] c = S.toCharArray();
len = c.length;
int result = 0;
Node temp = root;
for(int i=0;i<len;){
int num = c[i]-'a';
if(temp==root && temp.child[num]==null){
i++;
continue;
}
if(temp.child[num]!=null){
result += temp.child[num].count;
temp = temp.child[num];
i++;
}else{
temp = temp.fail;
result+= temp.count;
}
}
return result;
}
private static void insert(Node root,String s){
int len = s.length();
char[] c = s.toCharArray();
Node temp = root;
for(int i=0;i<len;i++){
if(temp.child[c[i]-'a']==null){
temp.child[c[i]-'a'] = new Node(c[i]-'a');
temp.child[c[i]-'a'].parent = temp;
}
temp = temp.child[c[i]-'a'];
}
temp.count++;
}
private static void adjustFail(Node root){
Queue<Node> queue = new LinkedList<>();
for(int i=0;i<26;i++){
if(root.child[i]==null){
continue;
}
root.child[i].fail = root;
queue.add(root.child[i]);
}
while(queue.size()!=0){
Node node = queue.poll();
for(int i=0;i<26;i++){
if(node.child[i]!=null){
node.child[i].fail = root;
Node fail = node.fail;
while(fail!=null){
if(fail.child[node.child[i].value]!=null){
node.child[i].fail = fail.child[node.child[i].value];
break;
}else{
fail = fail.fail;
}
}
queue.add(node.child[i]);
}
}
}
}
private static void print(Node root){
Node temp = root;
for(int i=0;i<26;i++){
if(root.child[i]!=null){
System.out.print(i+"&"+root.child[i].fail.value+" ");
print(root.child[i]);
}
}
System.out.println();
}
}
class Node{
Node[] child;
Node parent;
Node fail;
int value;
int count;
public Node(int value){
this.count = 0;
this.child = new Node[26];
this.value = value;
}
}