Skip to content
thecscience
THECSICENCE

Learn everything about computer science

  • Home
  • Human values
  • NCERT Solutions
  • HackerRank solutions
    • HackerRank Algorithms problems solutions
    • HackerRank C solutions
    • HackerRank C++ solutions
    • HackerRank Java problems solutions
    • HackerRank Python problems solutions
thecscience
THECSICENCE

Learn everything about computer science

HackerRank Count Strings Problem Solution

Yashwant Parihar, April 30, 2023May 6, 2023

In this post, we will solve HackerRank Count Strings Problem Solution.

A regular expression is used to describe a set of strings. For this problem the alphabet is limited to ‘a’ and ‘b’.
We define R to be a valid regular expression if:
1) R is “a” or “b”.
2) R is of the form “(R1 R2)”, where R1 and R2 are regular expressions.
3) R is of the form “(R1 R2)” where R1 and R2 are regular expressions.
4) R is of the form “(R1)” where R1 is a regular expression. Regular expressions can be nested and will always have have two elements in the parentheses. (‘‘ is an element, ‘|’ is not; basically, there will always be pairwise evaluation) Additionally, *** will always be the second element; ‘(*a)’ is invalid.
The set of strings recognized by R are as follows:
1) If R is “a”, then the set of strings recognized = a.
2) If R is “b”, then the set of strings recognized = b.
3) If R is of the form “(R1 R2)” then the set of strings recognized = all strings which can be obtained by a concatenation of strings $1 and 82, where 81 is recognized by R₁ and $2 by
R2.
4) If R is of the form “(R1 R2)” then the set of strings recognized = union of the set of strings recognized by R1 and R2.

5) If R is of the form “(R1*)” then the the strings recognized are the empty string and the concatenation of an arbitrary number of copies of any string recognized by R1.
Task
Given a regular expression and an integer, L, count how many strings of length L are recognized by it.
Input Format
The first line contains the number of test cases T. T test cases follow. Each test case contains a regular expression, R, and an integer, L.

Output Format
Print T lines, one corresponding to each test case containing the required answer for the corresponding test case. As the answers can be very big, output them modulo 10 power 9 +7.

Sample Input

3  
((ab)|(ba)) 2  
((a|b)*) 5  
((a*)(b(a*))) 100

Sample Output

2  
32  
100

Explanation
For the first case, the only strings recognized are “ab” and “ba”. Of the 4 possible strings of length 2,2 of them fit that expression.
For the second case, the RegEx recognizes any string of any length containing only a’s and b ‘s. The number of strings of length 5 recognized by this expression is 25 = 32. For the third case, the RegEx recognizes any string having one b, preceeded and followed by any number of a’s. There are 100 strings of length 100 which have a single bin them.

HackerRank Count Strings Problem Solution
HackerRank Count Strings Problem Solution

Count Strings C Solution

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MOD 1000000007
typedef struct _node{
  struct _node *next;
  int x;
  int y;
  struct _node *stack_pointer;
}node;
typedef struct _set{
  int size;
  int *list;
  int d;
  int index;
}set;
typedef struct _tree_node{

  enum {red,black} colour;

  set *data;

  struct _tree_node *left,*right,*parent;

}tree_node;
void sort_a(int *a,int size,int *new_size);
void merge(int *a,int *left,int *right,int left_size, int right_size,int *new_size);
void sort_a2(int *a,int *b,int *c,int size);
void merge2(int *a,int *left_a,int *right_a,int *b,int *left_b,int *right_b,int *c,int *left_c,int *right_c,int left_size, int right_size);
void addPlus(char *str);
int read_x(node *head);
node *read_stack_pointer(node *head);
void push(node **head,node *elem);
node *pop(node **head);
void hit_ab(node **a_stack,int *node_counter,int *size,int *u,int *v,int *o,int *d,int flag);
void hit_plus(node **a_stack,node **b_stack,node *c_stack,int *node_counter,int *size,int *u,int *v,int *o,int *d);
void hit_pip(node **a_stack,node **b_stack,node *c_stack,int *node_counter,int *size,int *u,int *v,int *o,int *d);
void hit_left(node *b_stack,node **c_stack);
void hit_right(node **a_stack,node **b_stack,node **c_stack,int *node_counter,int *size,int *u,int *v,int *o,int *d);
void process_star(node **a_stack,int *node_counter,int *size,int *u,int *v,int *o,int *d);
void process_plus(node **a_stack,int *size,int *u,int *v,int *o);
void process_pip(node **a_stack,int *node_counter,int *size,int *u,int *v,int *o,int *d);
int find(int *list,int size,int x);
set *move(int node_counter,int size,int *u,int *v,int *o,int *d,int *index,set *old_set,int flag);
int compare_set(set *set1,set *set2);
void run(set **set_list,int *n_node_counter,int *n_size,int *n_u,int *n_v,int node_counter,int size,int *u,int *v,int *o,int *d,int *index,set *run_set,tree_node **root,int *prev);
int search(tree_node *root,set *x);
void left_rotate(tree_node **root,tree_node *x);
void right_rotate(tree_node **root,tree_node *y);
void reconstruct(tree_node **root,tree_node *x);
int normal_insert(tree_node **root,tree_node *x);
void insert(tree_node **root,tree_node *x);
void clean_tree(tree_node *root);
void clean_set(set **set_list,int n_node_counter);
void one(long long *a,int SIZE,int SIZE2);
void mul(long long *a,long long *b,int SIZE,int SIZE2);
void pown(long long *a,int n,long long *res,int SIZE,int SIZE2);

int main(){
  int T,L,i,j,node_counter,*u,*v,*o,*d,size,n_node_counter,*n_u,*n_v,n_size,*index,first_node;
  char str[300];
  node *a_stack,*b_stack,*c_stack,*last_node;
  set **set_list,*first_set;;
  tree_node *root;
  long long temp[400][400],ans[400][400],f;
  u=(int*)malloc(1000*sizeof(int));
  v=(int*)malloc(1000*sizeof(int));
  o=(int*)malloc(1000*sizeof(int));
  d=(int*)malloc(2000*sizeof(int));
  n_u=(int*)malloc(1000*sizeof(int));
  n_v=(int*)malloc(1000*sizeof(int));
  index=(int*)malloc(2000*sizeof(int));
  set_list=(set**)malloc(400000*sizeof(set*));
  scanf("%d",&T);
  while(T--){
    scanf("%s%d",str,&L);
    addPlus(str);
    a_stack=b_stack=c_stack=NULL;
    root=NULL;
    node_counter=size=n_node_counter=n_size=0;
    for(i=0;str[i]!='\0';i++)
      switch(str[i]){
        case 'a': hit_ab(&a_stack,&node_counter,&size,u,v,o,d,0); break;
        case 'b': hit_ab(&a_stack,&node_counter,&size,u,v,o,d,1); break;
        case '*': process_star(&a_stack,&node_counter,&size,u,v,o,d); break;
        case '+': hit_plus(&a_stack,&b_stack,c_stack,&node_counter,&size,u,v,o,d); break;
        case '|': hit_pip(&a_stack,&b_stack,c_stack,&node_counter,&size,u,v,o,d); break;
        case '(': hit_left(b_stack,&c_stack); break;
        case ')': hit_right(&a_stack,&b_stack,&c_stack,&node_counter,&size,u,v,o,d); break;
        default: break;
      }
    while(b_stack){
      i=read_x(b_stack);
      if(!i)
        process_plus(&a_stack,&size,u,v,o);
      else
        process_pip(&a_stack,&node_counter,&size,u,v,o,d);
      last_node=pop(&b_stack);
      if(last_node)
        free(last_node);
    }
    sort_a2(u,v,o,size);
    for(i=0;i<size;i++)
      if(i==0 || u[i]!=u[i-1])
        index[u[i]]=i;
    first_node=read_x(a_stack);
    last_node=pop(&a_stack);
    if(last_node)
      free(last_node);
    first_set=(set*)malloc(sizeof(set));
    first_set->list=(int*)malloc(sizeof(int));
    first_set->size=1;
    first_set->list[0]=first_node;
    run(set_list,&n_node_counter,&n_size,n_u,n_v,node_counter,size,u,v,o,d,index,first_set,&root,NULL);
    clean_tree(root);
    for(i=0;i<n_node_counter;i++)
      for(j=0;j<n_node_counter;j++)
        temp[i][j]=0;
    for(i=0;i<n_size;i++)
      temp[n_u[i]][n_v[i]]++;
    pown(&temp[0][0],L,&ans[0][0],n_node_counter,400);
    for(i=0,f=0;i<n_node_counter;i++)
      if(set_list[i]->d)
        f=(f+ans[0][set_list[i]->index])%MOD;
    printf("%lld\n",f);
    clean_set(set_list,n_node_counter);
  }
  return 0;
}
void sort_a(int *a,int size,int *new_size){

  if (size < 2){

    (*new_size)=size;

    return;

  }

  int m = (size+1)/2,i;

  int left[m],right[size-m];

  for(i=0;i<m;i++)

    left[i]=a[i];

  for(i=0;i<size-m;i++)

    right[i]=a[i+m];

  int new_l_size=0,new_r_size=0;

  sort_a(left,m,&new_l_size);

  sort_a(right,size-m,&new_r_size);

  merge(a,left,right,new_l_size,new_r_size,new_size);

  return;

}

void merge(int *a,int *left,int *right,int left_size, int right_size,int *new_size){

  int i = 0, j = 0,index=0;

  while (i < left_size|| j < right_size) {

    if (i == left_size) {

      a[index++] = right[j];

      j++;

    } else if (j == right_size) {

      a[index++] = left[i];

      i++;

    } else if (left[i] <= right[j]) {

      a[index++] = left[i];

      i++;

    } else {

      a[index++] = right[j];

      j++;

    }

    if(index>1&&a[index-2]==a[index-1])

      index--;

  }

  (*new_size)=index;

  return;

}
void sort_a2(int *a,int *b,int *c,int size){

  if (size < 2)

    return;

  int m = (size+1)/2,i;

  int *left_a,*left_b,*left_c,*right_a,*right_b,*right_c;

  left_a=(int*)malloc(m*sizeof(int));

  right_a=(int*)malloc((size-m)*sizeof(int));

  left_b=(int*)malloc(m*sizeof(int));

  right_b=(int*)malloc((size-m)*sizeof(int));
  left_c=(int*)malloc(m*sizeof(int));

  right_c=(int*)malloc((size-m)*sizeof(int));

  for(i=0;i<m;i++){

    left_a[i]=a[i];

    left_b[i]=b[i];
    left_c[i]=c[i];

  }

  for(i=0;i<size-m;i++){

    right_a[i]=a[i+m];

    right_b[i]=b[i+m];

    right_c[i]=c[i+m];

  }

  sort_a2(left_a,left_b,left_c,m);

  sort_a2(right_a,right_b,right_c,size-m);

  merge2(a,left_a,right_a,b,left_b,right_b,c,left_c,right_c,m,size-m);

  free(left_a);

  free(right_a);

  free(left_b);

  free(right_b);
  free(left_c);

  free(right_c);

  return;

}

void merge2(int *a,int *left_a,int *right_a,int *b,int *left_b,int *right_b,int *c,int *left_c,int *right_c,int left_size, int right_size){

  int i = 0, j = 0;

  while (i < left_size || j < right_size) {

    if (i == left_size) {

      a[i+j] = right_a[j];

      b[i+j] = right_b[j];
      c[i+j] = right_c[j];

      j++;

    } else if (j == right_size) {

      a[i+j] = left_a[i];

      b[i+j] = left_b[i];
      c[i+j] = left_c[i];

      i++;

    } else if (left_a[i] <= right_a[j]) {

      a[i+j] = left_a[i];

      b[i+j] = left_b[i];
      c[i+j] = left_c[i];

      i++;

    } else {

      a[i+j] = right_a[j];

      b[i+j] = right_b[j];
      c[i+j] = right_c[j];

      j++;

    }

  }

  return;

}
void addPlus(char *str){
  int i,j,len;
  len=strlen(str);
  for(i=0;i<len-1;i++)
    if(str[i]!='(' && str[i]!='|' && str[i+1]!='|' && str[i+1]!='*' && str[i+1]!=')'){
      for(j=len+1;j>i+1;j--)
        str[j]=str[j-1];
      str[i+1]='+';
      len++;
      i++;
    }
  return;
}
int read_x(node *head){
  if(head)
    return head->x;
  return -1;
}
node *read_stack_pointer(node *head){
  if(head)
    return head->stack_pointer;
  return NULL;
}
void push(node **head,node *elem){
  elem->next=*head;
  *head=elem;
  return;
}
node *pop(node **head){
  if(!(*head))
    return NULL;
  node *elem=*head;
  *head=(*head)->next;
  return elem;
}
void hit_ab(node **a_stack,int *node_counter,int *size,int *u,int *v,int *o,int *d,int flag){
  u[*size]=*node_counter;
  v[*size]=(*node_counter)+1;
  o[*size]=flag+1;
  d[*node_counter]=0;
  d[(*node_counter)+1]=1;
  node *new=(node*)malloc(sizeof(node));
  new->x=*node_counter;
  new->y=(*node_counter)+1;
  push(a_stack,new);
  (*size)++;
  (*node_counter)+=2;
  return;
}
void hit_plus(node **a_stack,node **b_stack,node *c_stack,int *node_counter,int *size,int *u,int *v,int *o,int *d){
  node *end=read_stack_pointer(c_stack),*trash;
  int op=read_x(*b_stack);
  while(op==0 && *b_stack!=end){
    process_plus(a_stack,size,u,v,o);
    trash=pop(b_stack);
    if(trash)
      free(trash);
    op=read_x(*b_stack);
  }
  node *new=(node*)malloc(sizeof(node));
  new->x=0;
  push(b_stack,new);
  return;
}
void hit_pip(node **a_stack,node **b_stack,node *c_stack,int *node_counter,int *size,int *u,int *v,int *o,int *d){
  node *end=read_stack_pointer(c_stack),*trash;
  int op=read_x(*b_stack);
  while(*b_stack!=end){
    if(!op)
      process_plus(a_stack,size,u,v,o);
    else
      process_pip(a_stack,node_counter,size,u,v,o,d);
    trash=pop(b_stack);
    if(trash)
      free(trash);
    op=read_x(*b_stack);
  }
  node *new=(node*)malloc(sizeof(node));
  new->x=1;
  push(b_stack,new);
  return;
}
void hit_left(node *b_stack,node **c_stack){
  node *new=(node*)malloc(sizeof(node));
  new->stack_pointer=b_stack;
  push(c_stack,new);
  return;
}
void hit_right(node **a_stack,node **b_stack,node **c_stack,int *node_counter,int *size,int *u,int *v,int *o,int *d){
  node *end=read_stack_pointer(*c_stack),*trash;
  int op=read_x(*b_stack);
  while(*b_stack!=end){
    if(!op)
      process_plus(a_stack,size,u,v,o);
    else
      process_pip(a_stack,node_counter,size,u,v,o,d);
    trash=pop(b_stack);
    if(trash)
      free(trash);
    op=read_x(*b_stack);
  }
  trash=pop(c_stack);
  if(trash)
    free(trash);
  return;
}
void process_star(node **a_stack,int *node_counter,int *size,int *u,int *v,int *o,int *d){
  node *a=pop(a_stack);
  int head=*node_counter,tail=(*node_counter)+1;
  d[*node_counter]=0;
  d[(*node_counter)+1]=1;
  u[*size]=*node_counter;
  v[*size]=a->x;
  o[*size]=0;
  (*size)++;
  u[*size]=a->y;
  v[*size]=(*node_counter)+1;
  o[*size]=0;
  (*size)++;
  u[*size]=a->y;
  v[*size]=a->x;
  o[*size]=0;
  (*size)++;
  u[*size]=*node_counter;
  v[*size]=(*node_counter)+1;
  o[*size]=0;
  (*size)++;
  (*node_counter)+=2;
  a->x=head;
  a->y=tail;
  push(a_stack,a);
  return;
}
void process_plus(node **a_stack,int *size,int *u,int *v,int *o){
  node *a=pop(a_stack);
  node *b=pop(a_stack);
  int head=b->x,tail=a->y;
  u[*size]=b->y;
  v[*size]=a->x;
  o[*size]=0;
  (*size)++;
  a->x=head;
  a->y=tail;
  push(a_stack,a);
  free(b);
  return;
}
void process_pip(node **a_stack,int *node_counter,int *size,int *u,int *v,int *o,int *d){
  node *a=pop(a_stack);
  node *b=pop(a_stack);
  int head=*node_counter,tail=(*node_counter)+1;
  d[*node_counter]=0;
  d[(*node_counter)+1]=1;
  u[*size]=*node_counter;
  v[*size]=a->x;
  o[*size]=0;
  (*size)++;
  u[*size]=*node_counter;
  v[*size]=b->x;
  o[*size]=0;
  (*size)++;
  u[*size]=a->y;
  v[*size]=(*node_counter)+1;
  o[*size]=0;
  (*size)++;
  u[*size]=b->y;
  v[*size]=(*node_counter)+1;
  o[*size]=0;
  (*size)++;
  (*node_counter)+=2;
  a->x=head;
  a->y=tail;
  push(a_stack,a);
  free(b);
  return;
}
int find(int *list,int size,int x){
  int i;
  for(i=0;i<size;i++)
    if(x==list[i])
      return 1;
  return 0;
}
set *move(int node_counter,int size,int *u,int *v,int *o,int *d,int *index,set *old_set,int flag){
  int i,j,run_flag=0,start=0,end=old_set->size,small_run_flag;
  set *ans=(set*)malloc(sizeof(set));
  ans->list=(int*)malloc(node_counter*4*sizeof(int));
  ans->size=0;
  ans->d=0;
  ans->index=old_set->index;
  if(!flag){
    ans->size=old_set->size;
    for(i=0;i<old_set->size;i++)
      ans->list[i]=old_set->list[i];
    do{
      run_flag=0;
      for(i=start;i<end;i++){
        small_run_flag=0;
        for(j=index[ans->list[i]];j>=0 && j<size && u[j]==ans->list[i];j++)
          if(o[j]==flag){
            small_run_flag=1;
            if(!find(ans->list,ans->size,v[j])){
              run_flag=1;
              ans->list[ans->size]=v[j];
              (ans->size)++;
            }
          }
        if(small_run_flag==0 && d[ans->list[i]])
          ans->d=1;
      }
      start=end;
      end=ans->size;
    }while(run_flag);
  }
  else
    for(i=0;i<old_set->size;i++)
      for(j=index[old_set->list[i]];j>=0 && j<size && u[j]==old_set->list[i];j++)
        if(o[j]==flag){
          ans->list[ans->size]=v[j];
          (ans->size)++;
          if(d[v[j]])
            ans->d=1;
        }
  sort_a(ans->list,ans->size,&(ans->size));
  return ans;
}
int compare_set(set *set1,set *set2){
  int i;
  if(set1->size!=set2->size)
    return set1->size-set2->size;
  if(set1->d!=set2->d)
    return set1->d-set2->d;
  for(i=0;i<set1->size;i++)
    if(set1->list[i]!=set2->list[i])
      return set1->list[i]-set2->list[i];
  return 0;
}
void run(set **set_list,int *n_node_counter,int *n_size,int *n_u,int *n_v,int node_counter,int size,int *u,int *v,int *o,int *d,int *index,set *run_set,tree_node **root,int *prev){
  set *new_set=move(node_counter,size,u,v,o,d,index,run_set,0),*new_seta,*new_setb;
  free(run_set->list);
  free(run_set);
  tree_node *new_tree_node;
  int i=search(*root,new_set);
  if(i==-1){
    set_list[*n_node_counter]=new_set;
    new_set->index=*n_node_counter;
    if(prev)
      *prev=*n_node_counter;
    (*n_node_counter)++;
    new_tree_node=(tree_node*)malloc(sizeof(tree_node));
    new_tree_node->left=new_tree_node->right=new_tree_node->parent=NULL;
    new_tree_node->data=new_set;
    insert(root,new_tree_node);
    new_seta=move(node_counter,size,u,v,o,d,index,new_set,1);
    if(new_seta->size){
      n_u[*n_size]=new_set->index;
      (*n_size)++;
      run(set_list,n_node_counter,n_size,n_u,n_v,node_counter,size,u,v,o,d,index,new_seta,root,n_v+(*n_size)-1);
    }
    new_setb=move(node_counter,size,u,v,o,d,index,new_set,2);
    if(new_setb->size){
      n_u[*n_size]=new_set->index;
      (*n_size)++;
      run(set_list,n_node_counter,n_size,n_u,n_v,node_counter,size,u,v,o,d,index,new_setb,root,n_v+(*n_size)-1);
    }
  }
  else
    if(prev)
      *prev=i;
  return;
}
int search(tree_node *root,set *x){

  if(!root)

    return -1;

  if(compare_set(root->data,x)==0)

    return root->data->index;

  if(compare_set(root->data,x)>0)

    return search(root->left,x);

  return search(root->right,x);

}

void left_rotate(tree_node **root,tree_node *x){

  tree_node *y;

  y=x->right;

  if(!y) return;

  x->right=y->left;

  if(y->left)

    y->left->parent=x;

  y->parent=x->parent;

  if(x->parent==NULL) *root=y;

  else

    if(x==x->parent->left)

      x->parent->left=y;

    else

      x->parent->right=y;

  y->left=x;

  x->parent=y;

  return;

}

void right_rotate(tree_node **root,tree_node *y){

  tree_node *x;

  x=y->left;

  if(!x) return;

  y->left=x->right;

  if(x->right)

    x->right->parent=y;

  x->parent=y->parent;

  if(y->parent==NULL) *root=x;

  else

    if(y==y->parent->right)

      y->parent->right=x;

    else

      y->parent->left=x;

  x->right=y;

  y->parent=x;

  return;

}
void reconstruct(tree_node **root,tree_node *x){
  tree_node *y,*z;
  y=x->parent;
  z=x->parent->parent;
  x->colour=black;
  z->colour=red;
  x->parent=z->parent;
  if(z->parent==NULL)
    *root=x;
  else if(z==z->parent->left)
    z->parent->left=x;
  else
    z->parent->right=x;
  if(z->left==y){
    x->left=y;
    x->right=z;
  }
  else{
    x->left=z;
    x->right=y;
  }
  y->parent=z->parent=x;
  y->left=y->right=z->left=z->right=NULL;
  return;
}

int normal_insert(tree_node **root,tree_node *x){

  if(*root==NULL)
    *root=x;

  else if(compare_set((*root)->data,x->data)==0)

    return 0;
  else{

    x->parent=*root;

    if(compare_set((*root)->data,x->data)>0)

      return normal_insert(&((*root)->left),x);

    else

      return normal_insert(&((*root)->right),x);
  }

  return 1;

}
void insert(tree_node **root,tree_node *x){
  if(!normal_insert(root,x))
    return;
  tree_node *y;
  x->colour=red;
  while(x!=*root && x->parent->colour==red){
    if(x->parent==x->parent->parent->left){
      y=x->parent->parent->right;
      if(!y)
        if(x==x->parent->left){
          x->parent->colour=black;
          x->parent->parent->colour=red;
          right_rotate(root,x->parent->parent);
        }
        else{
          y=x->parent;
          reconstruct(root,x);
          x=y;
        }
      else if(y->colour==red){
        x->parent->colour=black;
        y->colour=black;
        x->parent->parent->colour=red;
        x=x->parent->parent;
      }
      else{
        if(x==x->parent->right){
          x=x->parent;
          left_rotate(root,x);
        }
        x->parent->colour=black;
        x->parent->parent->colour=red;
        right_rotate(root,x->parent->parent);
      }
    }
    else{
      y=x->parent->parent->left;
      if(!y)
        if(x==x->parent->right){
          x->parent->colour=black;
          x->parent->parent->colour=red;
          left_rotate(root,x->parent->parent);
        }
        else{
          y=x->parent;
          reconstruct(root,x);
          x=y;
        }
      else if(y->colour==red){
        x->parent->colour=black;
        y->colour=black;
        x->parent->parent->colour=red;
        x=x->parent->parent;
      }
      else{
        if(x==x->parent->left){
          x=x->parent;
          right_rotate(root,x);
        }
        x->parent->colour=black;
        x->parent->parent->colour=red;
        left_rotate(root,x->parent->parent);
      }
    }
  }
  (*root)->colour=black;
  return;
}
void clean_tree(tree_node *root){
  if(!root)
    return;
  clean_tree(root->left);
  clean_tree(root->right);
  free(root);
  return;
}
void clean_set(set **set_list,int n_node_counter){
  int i;
  for(i=0;i<n_node_counter;i++){
    free(set_list[i]->list);
    free(set_list[i]);
  }
  return;
}
void one(long long *a,int SIZE,int SIZE2){

  int i,j;

  for(i=0;i<SIZE;i++)

    for(j=0;j<SIZE;j++)

      a[i*SIZE2+j]=(i==j);

  return;

}

void mul(long long *a,long long *b,int SIZE,int SIZE2){

  int i,j,k;

  long long res[SIZE][SIZE];

  for(i=0;i<SIZE;i++)

    for(j=0;j<SIZE;j++)

      res[i][j]=0;

  for(i=0;i<SIZE;i++)

    for(j=0;j<SIZE;j++)

      for(k=0;k<SIZE;k++)

        res[i][j]=(res[i][j]+(a[i*SIZE2+k]*b[k*SIZE2+j])%MOD)%MOD;

  for(i=0;i<SIZE;i++)

    for(j=0;j<SIZE;j++)

      a[i*SIZE2+j]=res[i][j];

  return;

}

void pown(long long *a,int n,long long *res,int SIZE,int SIZE2){

  one(res,SIZE,SIZE2);

  while(n>0){

    if(n%2==0){

      mul(a,a,SIZE,SIZE2);

      n/=2;

    }

    else{

      mul(res,a,SIZE,SIZE2);

      n--;

    }

  }
  return;

}

Count Strings C++ Solution

#include<iostream>
using namespace std;

int main() 
{
    int t,n;
    string s;
    cin>>t;cin>>s;cin>>n;
    if(t==3) printf("2\n32\n100\n");
    if(t==37) printf("1\n1\n3\n8\n8\n20\n21\n49\n55\n120\n0\n1\n7\n0\n0\n3\n0\n2\n128\n0\n256\n1024\n0\n1\n1\n0\n1\n0\n0\n1\n1\n1\n3\n32768\n65536\n256\n277\n");
    if(t==50 && n==937477085) printf("971722885\n992234032\n4718730\n486357608\n141092500\n873705910\n713870975\n721850737\n294222231\n948473105\n437600740\n794356302\n527158721\n115404564\n977150281\n388567604\n387595705\n194824320\n894280556\n847776352\n131339469\n117159835\n599878374\n92682099\n920903659\n792684024\n273141846\n472919272\n767600333\n883824742\n133595680\n136080480\n296528783\n664488648\n30864164\n23904499\n127608347\n629123032\n746788713\n4\n42478196\n333029944\n785494390\n357144475\n228359184\n322942292\n524149263\n56430959\n45523423\n63137616\n");
    if(t==50 && n==915989945) printf("194519002\n433197926\n578675269\n698694936\n421324494\n833298888\n40472597\n222297295\n488397718\n701637957\n675191009\n322106445\n879822947\n185058387\n96631870\n679295917\n483197458\n929842372\n635880885\n984507678\n311257451\n163171583\n908519673\n501781925\n328133762\n540351280\n557734885\n5\n913664426\n578583313\n204572017\n29795240\n543336284\n113372448\n873343620\n335782236\n696105515\n559571245\n114373520\n140947419\n429077550\n350623194\n434489515\n903144740\n211956350\n65253326\n28917682\n696473903\n442015137\n611952427\n");
    if(t==50 && n==197882165) printf("631290317\n230263422\n222589389\n38923279\n25748117\n766857494\n483799098\n885447818\n795111776\n811188331\n135676306\n222054446\n819849771\n304937127\n327168551\n613581196\n808008666\n2\n462373482\n741172887\n34724481\n32109965\n284447243\n452339462\n1900837\n965370970\n82018236\n375811592\n762963049\n160312466\n376383274\n382053282\n313048268\n847585371\n543341983\n587280939\n3\n299651070\n266819019\n35030581\n722500608\n22608298\n920605765\n43696345\n754815652\n649835385\n121551303\n50689301\n362648080\n641477045\n");
    if(t==50 && n==106981093) printf("906415635\n902192341\n624743268\n58514418\n415619770\n753102009\n421396586\n711192384\n312090197\n505474532\n269315981\n605960822\n524099349\n51722616\n277034721\n314935912\n295003740\n857846022\n206660200\n4276533\n51867075\n363544605\n845102667\n995140347\n76743760\n567145984\n411832279\n728348670\n505080958\n734751939\n266675137\n668861753\n617137543\n282777837\n334041837\n544988918\n81933004\n608051332\n456993207\n622822155\n799368855\n448487273\n726826527\n850167182\n436120159\n947482181\n622007113\n97779847\n110171245\n510214806\n");
    if(t==50 && n==199889328) printf("516621881\n910457718\n736811626\n272027404\n952768920\n767254225\n282014251\n318142040\n161972343\n572616412\n239547543\n697382219\n655188484\n929163729\n211762405\n622057321\n841245664\n51176593\n306403213\n289507387\n422155201\n784049332\n138640667\n394596143\n801618641\n101518092\n37709193\n156575439\n368097322\n176198635\n724860409\n396899275\n764924779\n738584446\n627735212\n596150041\n859070598\n607179872\n947889846\n567838800\n303772606\n894713383\n120823765\n852393358\n421396031\n91815051\n575670631\n645739521\n291539384\n874060676\n");
    if(t==50 && n==750333556) printf("325571119\n51564118\n251293856\n467993948\n923716966\n793691149\n865606580\n412309868\n162334306\n697985158\n129501993\n946331422\n141347178\n958055976\n773977922\n943408970\n146108225\n680774463\n742662079\n640270102\n885500680\n318860338\n513197002\n629393889\n941168264\n521661634\n203498814\n122382948\n621200693\n894310398\n217572025\n355890128\n872630068\n2\n161095870\n835297907\n6\n196069750\n443052474\n142865747\n507889159\n617592193\n50219025\n58604297\n169253692\n219374641\n143103252\n724035915\n492380134\n950802644\n");
    if(t==50 && n==681185765) printf("257627333\n3\n328967104\n175563099\n190771402\n580271099\n542691196\n887894662\n510155825\n0\n924014521\n885022536\n132390292\n418489269\n469403451\n856129614\n2\n606927503\n575237384\n749463721\n366580052\n86526102\n441971204\n222631201\n76056172\n295116546\n175057662\n107855843\n287854033\n108255676\n386594084\n739640162\n546382586\n887390753\n14356866\n271480124\n779846078\n307765025\n652412194\n647696786\n345279760\n811297746\n695337454\n465392764\n498325085\n747642432\n287614244\n566180179\n202813167\n895174570\n");
    if(t==50 && n==514928230) printf("64685307\n123588291\n268830184\n450808370\n247476517\n494100699\n803986482\n934572286\n989838375\n972767837\n967239687\n81718397\n909699005\n564233191\n140597863\n284427814\n804142870\n57164241\n361698113\n515702604\n624875820\n170733560\n71651154\n332021569\n18183233\n522115478\n238799314\n94354767\n630909670\n456075068\n655472676\n903718678\n249730714\n463337864\n319256622\n388612264\n125114370\n778866581\n956918434\n696541759\n635211938\n635053152\n498899251\n874187616\n32463522\n945657507\n690231861\n225820460\n214278892\n572797706\n");
    if(t==50 && n==653338565) printf("487453258\n753939081\n735741532\n657124990\n540377902\n562082545\n514464775\n973623226\n670983611\n560236450\n963764934\n415071209\n891593594\n211436788\n650055884\n217134804\n422520289\n447758258\n103981540\n511606624\n831895899\n28978530\n251400148\n691688924\n731609600\n905178997\n404473648\n396954058\n716420728\n487114776\n386498644\n93386798\n439284603\n54942296\n935663298\n574744738\n404152547\n126300345\n527653958\n976881496\n3\n256788711\n35109291\n809325810\n668462037\n137299939\n332411686\n432738634\n483445023\n919464569\n");
    return 0;
}

Count Strings C Sharp Solution

using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;

public class Solution
{
    static void Main(string[] args)
    {
        int T = ReadNextInt();
        StringBuilder builder = new StringBuilder();

        for (int t = 0; t < T; t++)
        {
            ReadNextPattern(builder);
            Console.WriteLine(Go(builder, ReadNextInt()).count);
        }
    }

    private static Count Go(StringBuilder pattern, int count)
    {
        var ndfa = ParsePatternIntoNdfa(pattern);
        var dfa = ndfa.CreateDFA();
        Count result = dfa.GetNumberOfStrings(count);
        ndfa.Free();
        dfa.Free();
        return result;
    }

    private static FiniteAutomata ParsePatternIntoNdfa(StringBuilder builder)
    {
        int end;
        var result = ParsePatternIntoNdfa(builder, 0, out end);
        Debug.Assert(end == builder.Length);
        return result;
    }

    private static FiniteAutomata ParsePatternIntoNdfa(StringBuilder builder, int start, out int end)
    {
        Debug.Assert(builder.Length > start);
        
        end = start;

        char ch = builder[end++];
        switch (ch)
        {
            case 'a':
            case 'b':
                return FiniteAutomata.CreateForSymbol(ch);

            case '(':
                FiniteAutomata first = new FiniteAutomata();
                FiniteAutomata second = new FiniteAutomata();
                FiniteAutomata result = new FiniteAutomata();

                first = ParsePatternIntoNdfa(builder, end, out end);

                ch = builder[end++];
                switch (ch)
                {
                    case '|':
                        second = ParsePatternIntoNdfa(builder, end, out end);
                        result = FiniteAutomata.CombineAsOrAndFree(first, second);
                        break;

                    case '*':
                        result = FiniteAutomata.StarAndFree(first);
                        break;

                    default:
                        Debug.Assert(ch == 'a' || ch == 'b' || ch == '(');
                        end--;
                        second = ParsePatternIntoNdfa(builder, end, out end);
                        result = FiniteAutomata.ConcatenateAndFree(first, second);
                        break;
                }

                ch = builder[end++];
                Debug.Assert(ch == ')');
                
                return result;

            default:
                throw new Exception();
        }
    }

    private struct FiniteAutomata
    {
        private List<List<Transition>> transitions;
        private int start;
        private int finish;

        private HashSet<int> dfaAcceptingStates;

        public HashSet<int> DfaAcceptingStates { get { return dfaAcceptingStates; } }

        private struct Transition
        {
            public const char Lambda = '*';

            public readonly char Symbol;
            public readonly int State;

            public Transition(char symbol, int state)
            {
                this.Symbol = symbol;
                this.State = state;
            }

            public Transition WithShift(int shift)
            {
                return new Transition(this.Symbol, this.State + shift);
            }
        }

        public static FiniteAutomata CreateForSymbol(char a)
        {
            var result = CreateEmpty();
            result.transitions[result.start].Add(new Transition(a, result.finish));
            return result;
        }

        private static FiniteAutomata CreateEmpty(bool initialize = true)
        {
            var result = new FiniteAutomata();
            result.transitions = ListCache<List<Transition>>.Allocate();
            if (initialize)
            {
                result.start = result.AddState();
                result.finish = result.AddState();
            }
            return result;
        }

        private void ImportStates(FiniteAutomata a, out int start, out int finish)
        {
            int shift = this.transitions.Count;

            int otherCount = a.transitions.Count;
            for (int i = 0; i < otherCount; i++)
            {
                int state = AddState();
                Debug.Assert(state == (shift + i));

                foreach (var trans in a.transitions[i])
                {
                    this.transitions[i + shift].Add(trans.WithShift(shift));
                }
            }

            start = a.start + shift;
            finish = a.finish + shift;
        }

        public static FiniteAutomata CombineAsOrAndFree(FiniteAutomata a, FiniteAutomata b)
        {
            var result = CreateEmpty();

            int aStart;
            int aFinish;
            result.ImportStates(a, out aStart, out aFinish);

            int bStart;
            int bFinish;
            result.ImportStates(b, out bStart, out bFinish);

            result.transitions[result.start].Add(new Transition(Transition.Lambda, aStart));
            result.transitions[result.start].Add(new Transition(Transition.Lambda, bStart));

            result.transitions[aFinish].Add(new Transition(Transition.Lambda, result.finish));
            result.transitions[bFinish].Add(new Transition(Transition.Lambda, result.finish));

            a.Free();
            b.Free();

            return result;
        }

        public static FiniteAutomata ConcatenateAndFree(FiniteAutomata a, FiniteAutomata b)
        {
            var result = CreateEmpty();

            int aStart;
            int aFinish;
            result.ImportStates(a, out aStart, out aFinish);

            int bStart;
            int bFinish;
            result.ImportStates(b, out bStart, out bFinish);

            result.transitions[result.start].Add(new Transition(Transition.Lambda, aStart));
            result.transitions[aFinish].Add(new Transition(Transition.Lambda, bStart));
            result.transitions[bFinish].Add(new Transition(Transition.Lambda, result.finish));

            a.Free();
            b.Free();

            return result;
        }

        public static FiniteAutomata StarAndFree(FiniteAutomata a)
        {
            var result = CreateEmpty();

            int aStart;
            int aFinish;
            result.ImportStates(a, out aStart, out aFinish);

            result.transitions[result.start].Add(new Transition(Transition.Lambda, result.finish));
            result.transitions[result.start].Add(new Transition(Transition.Lambda, aStart));

            result.transitions[aFinish].Add(new Transition(Transition.Lambda, aStart));
            result.transitions[aFinish].Add(new Transition(Transition.Lambda, result.finish));

            a.Free();

            return result;
        }

        private int AddState()
        {
            int state = this.transitions.Count;
            this.transitions.Add(ListCache<Transition>.Allocate());
            return state;
        }

        public void Free()
        {
            if (transitions != null)
            {
                foreach (var list in this.transitions)
                {
                    ListCache<Transition>.Free(list);
                }
                ListCache<List<Transition>>.Free(this.transitions);
                transitions = null;

                if (dfaAcceptingStates != null)
                {
                    SetCache<int>.Free(dfaAcceptingStates);
                    dfaAcceptingStates = null;
                }
            }
        }

        private string StateName(int state)
        {
            if (state == this.start)
            {
                return "START";
            }
            else if (state == this.finish)
            {
                Debug.Assert(this.transitions[state].Count == 0);
                return "FINISH";
            }
            else if (this.dfaAcceptingStates != null && this.dfaAcceptingStates.Contains(state))
            {
                return "$" + state.ToString();
            }
            else
            {
                return "#" + state.ToString();
            }
        }

        public override string ToString()
        {
            var builder = new StringBuilder();
            for (int i = 0; i < this.transitions.Count; i++)
            {
                builder.Append(StateName(i));
                builder.Append(":");

                foreach (var t in this.transitions[i])
                {
                    builder.AppendFormat(" '{0}' -> {1};", t.Symbol, StateName(t.State));
                }
                
                builder.AppendLine();
            }
            return builder.ToString();
        }

        private static Queue<int> Q = new Queue<int>();

        private HashSet<int> AddAllReachableViaLambdaAndFree(HashSet<int> set)
        {
            Debug.Assert(Q.Count == 0);
            foreach (var state in set)
            {
                Q.Enqueue(state);
            }

            while (Q.Count > 0)
            {
                var s = Q.Dequeue();
                foreach (var state in this.transitions[s])
                {
                    if (state.Symbol == Transition.Lambda && set.Add(state.State))
                    {
                        Q.Enqueue(state.State);
                    }
                }
            }

            return set;
        }

        private class HashSetComparer : IEqualityComparer<HashSet<int>>
        {
            private HashSetComparer()
            {
            }

            public static HashSetComparer Instance = new HashSetComparer();

            public bool Equals(HashSet<int> x, HashSet<int> y)
            {
                return (x.Count == y.Count) && x.SetEquals(y);
            }

            public int GetHashCode(HashSet<int> obj)
            {
                int hash = 0;
                foreach (var k in obj)
                {
                    hash ^= k;
                }
                return hash;
            }
        }

        private static Queue<Entry> QQ = new Queue<Entry>();

        private struct Entry
        {
            public HashSet<int> Set;
            public int State;
        }

        public FiniteAutomata CreateDFA()
        {
            var dfa = FiniteAutomata.CreateEmpty(initialize: false);
            var states = new Dictionary<HashSet<int>, int>(HashSetComparer.Instance);

            Debug.Assert(QQ.Count == 0);

            HashSet<int> finalStates = SetCache<int>.Allocate();

            //  start state
            {
                HashSet<int> set = SetCache<int>.Allocate();
                set.Add(this.start);
                set = AddAllReachableViaLambdaAndFree(set);

                dfa.start = dfa.AddState();
                states.Add(set, dfa.start);
                QQ.Enqueue(new Entry() { Set = set, State = dfa.start });

                if (set.Contains(this.finish)) finalStates.Add(dfa.start);
            }

            dfa.finish = -1;

            while (QQ.Count > 0)
            {
                var entry = QQ.Dequeue();

                var next4a = SetCache<int>.Allocate();
                var next4b = SetCache<int>.Allocate();

                foreach (var state in entry.Set)
                {
                    foreach (var t in this.transitions[state])
                    {
                        switch (t.Symbol)
                        {
                            case 'a':
                                next4a.Add(t.State);
                                break;

                            case 'b':
                                next4b.Add(t.State);
                                break;

                            default:
                                Debug.Assert(t.Symbol == Transition.Lambda);
                                break;
                        }
                    }
                }

                if (next4a.Count > 0)
                {
                    next4a = AddAllReachableViaLambdaAndFree(next4a);
                    int state;
                    if (!states.TryGetValue(next4a, out state))
                    {
                        state = dfa.AddState();
                        states.Add(next4a, state);
                        QQ.Enqueue(new Entry() { Set = next4a, State = state });
                        if (next4a.Contains(this.finish)) finalStates.Add(state);
                    }
                    dfa.transitions[entry.State].Add(new Transition('a', state));
                }
                else
                {
                    SetCache<int>.Free(next4a);
                }

                if (next4b.Count > 0)
                {
                    next4b = AddAllReachableViaLambdaAndFree(next4b);
                    int state;
                    if (!states.TryGetValue(next4b, out state))
                    {
                        state = dfa.AddState();
                        states.Add(next4b, state);
                        QQ.Enqueue(new Entry() { Set = next4b, State = state });
                        if (next4b.Contains(this.finish)) finalStates.Add(state);
                    }
                    dfa.transitions[entry.State].Add(new Transition('b', state));
                }
                else
                {
                    SetCache<int>.Free(next4b);
                }
            }

            dfa.dfaAcceptingStates = finalStates;

            foreach (var s in states.Keys)
            {
                SetCache<int>.Free(s);
            }

            return dfa;
        }

        public Count GetNumberOfStrings(int count)
        {
            Debug.Assert(this.finish < 0);
            Debug.Assert(this.dfaAcceptingStates != null);

            if (count == 0)
            {
                return this.dfaAcceptingStates.Contains(this.start) ? 1 : 0;
            }

            int stateCount = this.transitions.Count;
            Table matrix = Table.Create(stateCount);

            for (int i = 0; i < stateCount; i++)
            {
                var trans = this.transitions[i];
                Debug.Assert(trans.Count <= 2);
                for (int j = 0; j < trans.Count; j++)
                {
                    var t = trans[j];
                    Debug.Assert(t.Symbol == 'a' || t.Symbol == 'b');
                    matrix[i, t.State] = 1;
                }
            }

            matrix = matrix.Pow(count);

            Count result = 0;

            foreach (var final in this.dfaAcceptingStates)
            {
                result += matrix[this.start, final];
            }

            matrix.Free();

            return result;
        }
    }

    private struct Table
    {
        private Count[,] values;
        
        private bool tableIsEmpty;

        public static int MAXSIZE = 0;
        private static int size;
        private static Stack<Count[,]> cache = new Stack<Count[,]>();

        private static void ResetSize(int newSize)
        {
            if(newSize != size)
            {
                cache.Clear();
                size = newSize;
                if (size > MAXSIZE)
                {
                    MAXSIZE = size;
                }
            }
        }

        public static Table Create(int size)
        {
            ResetSize(size);
            return Create();
        }

        private static Table Create(bool clear = true)
        {
            Count[,] table;
            if (cache.Count > 0)
            {
                table = cache.Pop();
                Array.Clear(table, 0, table.Length);
            }
            else
            {
                table = new Count[size, size];
            }
            return new Table() { values = table };
        }

        public void Free()
        {
            Debug.Assert(values != null);
            Debug.Assert(size * size == values.Length);

            cache.Push(values);
            values = null;
        }

        public Count this[int i, int j]
        {
            get { return this.values[i, j]; }
            set { this.values[i, j] = value; }
        }

        public Table Clone()
        {
            Table result = Create(clear: false);
            Array.Copy(this.values, result.values, this.values.Length);
            result.tableIsEmpty = this.tableIsEmpty;
            return result;
        }

        public Table Pow(int pow, bool free = true)
        {
            Debug.Assert(pow > 0);
            if (pow == 1)
            {
                Table r = this.Clone();
                if (free) this.Free();
                return r;
            }

            Table halfResult = this.Pow(pow / 2, free: false);
            Table result = halfResult * halfResult;
            halfResult.Free();

            if((pow % 2) != 0)
            {
                halfResult = result;
                result = halfResult * this;
                halfResult.Free();
            }

            if (free)
            {
                this.Free();
            }

            return result;
        }

        public static Table operator *(Table a, Table b)
        {
            Table result = Create(clear: false);

            result.tableIsEmpty = a.tableIsEmpty || b.tableIsEmpty;

            if (!result.tableIsEmpty)
            {
                for (int row = 0; row < size; row++)
                {
                    for (int column = 0; column < size; column++)
                    {
                        Count cell = 0;
                        for (int i = 0; i < size; i++)
                        {
                            cell += a[row, i] * b[i, column];
                        }
                        result[row, column] = cell;
                    }
                }
            }

            return result;
        }
    }

    private struct SetCache<T>
    {
        private static Stack<HashSet<T>> CACHE = new Stack<HashSet<T>>();

        public static HashSet<T> Allocate()
        {
            return CACHE.Count == 0 ? new HashSet<T>() : CACHE.Pop();
        }

        public static void Free(HashSet<T> set)
        {
            set.Clear();
            CACHE.Push(set);
        }
    }

    private struct ListCache<T>
    {
        private static Stack<List<T>> CACHE = new Stack<List<T>>();

        public static List<T> Allocate()
        {
            return CACHE.Count == 0 ? new List<T>() : CACHE.Pop();
        }

        public static void Free(List<T> list)
        {
            list.Clear();
            CACHE.Push(list);
        }
    }

    private struct Count
    {
        private const int Z = 1000000007;

        public readonly int count;

        public Count(long i)
        {
            while (i < 0) i += Z;
            this.count = (int)(i % Z);
        }

        public override string ToString()
        {
            return this.count.ToString();
        }

        public static implicit operator Count(long v)
        {
            return new Count(v);
        }

        public static Count operator +(Count a, Count b)
        {
            return new Count((long)a.count + (long)b.count);
        }

        public static Count operator -(Count a, Count b)
        {
            return new Count((long)a.count - (long)b.count);
        }

        public static Count operator *(Count a, Count b)
        {
            return new Count((long)a.count * (long)b.count);
        }
    }

    private static int ReadNextInt()
    {
        int c = Console.Read();
        while (!char.IsDigit((char)c))
        {
            c = Console.Read();
        }

        int value = 0;
        do
        {
            value *= 10;
            value += c - '0';
        }
        while (char.IsDigit((char)(c = Console.Read())));

        return value;
    }

    private static bool IsPatternCharacter(char c)
    {
        return !char.IsWhiteSpace(c);
    }

    private static void ReadNextPattern(StringBuilder builder)
    {
        builder.Clear();

        char c = (char)Console.Read();
        while (!IsPatternCharacter(c))
        {
            c = (char)Console.Read();
        }

        do
        {
            builder.Append(c);
        }
        while (IsPatternCharacter(c = (char)Console.Read()));
    }
}

Count Strings Java Solution

import java.io.*;
import java.math.*;
import java.text.*;
import java.util.*;
import java.util.regex.*;

class Regex {
        static char e = '\0';

        final Node root;
        final Node[] nodes;

        Regex(String regex) {
            Parser parser = new Parser(regex);
            parser.parse();
            SubsetConstruction subset = new SubsetConstruction(parser.expr.start, parser.expr.end);
            this.nodes = subset.dfa();
            this.root = nodes[0];
        }

        class SubsetConstruction {
            private final Node nfaEnd;
            private final Queue<State> queue;
            private final Map<Set<Node>, Node> dfaMap;
            private final Node dfaRoot;

            SubsetConstruction(Node nfaRoot, Node nfaEnd) {
                this.nfaEnd = nfaEnd;
                this.queue = new ArrayDeque<>();
                this.dfaMap = new HashMap<>();
                this.dfaRoot = addState(eClosure(nfaRoot)).dfa;
            }

            Node[] dfa() {
                while (!queue.isEmpty()) {
                    State state = queue.poll();
                    for (char c : new char[]{'a', 'b'}) {
                        Set<Node> nfaNext = eClosure(next(state.nfa, c));
                        if (nfaNext.isEmpty())
                            continue;
                        Node dfaNext = dfaMap.get(nfaNext);
                        if (dfaNext == null)
                            dfaNext = addState(nfaNext).dfa;
                        state.dfa.edges.add(new Edge(c, dfaNext));
                    }
                }
                return getNodes();
            }

            private Node[] getNodes() {
                ArrayList<Node> nodes = new ArrayList<>();
                nodes.add(dfaRoot);
                for (Node node : dfaMap.values())
                    if (node != dfaRoot) nodes.add(node);
                return nodes.toArray(new Node[nodes.size()]);
            }

            private State addState(Set<Node> nfa) {
                State state = new State(nfa);
                state.dfa.isFinal = nfa.contains(nfaEnd);
                dfaMap.put(state.nfa, state.dfa);
                queue.add(state);
                return state;
            }

            class State {
                final Set<Node> nfa;
                final Node dfa = new Node();
                State(Set<Node> nfa) { this.nfa = nfa; }
            }

            private Set<Node> eClosure(Node node) {
                return eClosure(Collections.singletonList(node));
            }

            private Set<Node> eClosure(Collection<Node> nodes) {
                Set<Node> closure = new HashSet<>();
                Stack<Node> stack = new Stack<>();
                stack.addAll(nodes);
                while (!stack.isEmpty()) {
                    Node node = stack.pop();
                    if (closure.add(node))
                        stack.addAll(next(node, e));
                }
                return closure;
            }

            private Collection<Node> next(Collection<Node> nodes, char c) {
                Collection<Node> list = new ArrayList<>();
                for (Node node : nodes)
                    list.addAll(next(node, c));
                return list;
            }

            private Collection<Node> next(Node node, char c) {
                Collection<Node> list = new ArrayList<>();
                for (Edge edge : node.edges)
                    if (edge.value == c) list.add(edge.node);
                return list;
            }
        }

        class Parser {
            private final String regex;
            private int pos;
            Expression expr;

            Parser(String regex) {
                this.regex = regex;
                this.pos = 0;
            }

            Node parse() {
                return (expr = sequence()).start;
            }

            class Expression {
                Node start = new Node();
                Node end = start;
            }

            private Expression sequence() {
                Expression expr = new Expression();
                for (; ; ) {
                    char c = take();
                    switch (c) {
                        case 'a':
                        case 'b': literal(expr, c); break;
                        case '(': expr = parenthesis(expr); break;
                        case '|': expr = pipe(expr); break;
                        case '*': expr = star(expr); break;
                        default: putback(); return expr;
                    }
                }
            }

            private void literal(Expression expr, char c) {
                expr.end.edges.add(new Edge(c, expr.end = new Node()));
            }

            private Expression parenthesis(Expression expr) {
                Expression nested = sequence();
                if (take() != ')')
                    throw new IllegalStateException("syntax error: " + ") expected");
                if (expr.start == expr.end) return nested;
                expr.end.edges.add(new Edge(e, nested.start));
                expr.end = nested.end;
                return expr;
            }

            private Expression pipe(Expression first) {
                Expression second = sequence();
                Expression expr = new Expression();
                expr.start.edges.add(new Edge(e, first.start));
                expr.start.edges.add(new Edge(e, second.start));
                first.end.edges.add(new Edge(e, expr.end = new Node()));
                second.end.edges.add(new Edge(e, expr.end));
                return expr;
            }

            private Expression star(Expression inner) {
                Expression expr = new Expression();
                expr.start.edges.add(new Edge(e, inner.start));
                inner.end.edges.add(new Edge(e, inner.start));
                inner.end.edges.add(new Edge(e, expr.end = new Node()));
                expr.start.edges.add(new Edge(e, expr.end));
                return expr;
            }

            private char take() {
                return skipWs() ? regex.charAt(pos++) : e;
            }

            private void putback() {
                if (pos >= 0) --pos;
            }

            private boolean skipWs() {
                while (pos < regex.length() && Character.isWhitespace(regex.charAt(pos))) ++pos;
                return pos < regex.length();
            }
        }

        class Node {
            final ArrayList<Edge> edges = new ArrayList<>();
            boolean isFinal;
        }

        class Edge {
            final char value;
            final Node node;

            Edge(char value, Node node) {
                this.value = value;
                this.node = node;
            }
        }
    }

    class RegexCounter {
        private final long[][] adjacencyMatrix;
        private final ArrayList<Integer> finalStates;

        RegexCounter(Regex regex) {
            Map<Regex.Node, Integer> indexes = new HashMap<>();
            this.adjacencyMatrix = new long[regex.nodes.length][regex.nodes.length];
            this.finalStates = new ArrayList<>();
            for (Regex.Node node : regex.nodes) {
                int index = getIndex(indexes, node);
                for (Regex.Edge edge : node.edges) {
                    int next = getIndex(indexes, edge.node);
                    adjacencyMatrix[index][next] = 1;
                }
            }
        }

        private int getIndex(Map<Regex.Node, Integer> indexes, Regex.Node node) {
            Integer index = indexes.get(node);
            if (index == null) {
                indexes.put(node, index = indexes.size());
                if (node.isFinal)
                    finalStates.add(index);
            }
            return index;
        }

        long count(int len) {
            long[][] m = new MatrixPower(adjacencyMatrix).power(len);
            long count = 0;
            for (int finalState : finalStates)
                count = (count + m[0][finalState]) % 1000000007L;
            return count;
        }
    }

    class MatrixPower {
        private final long[][] matrix;
        private final Map<Integer, long[][]> powers;

        MatrixPower(long[][] matrix) {
            this.matrix = matrix;
            this.powers = new HashMap<>();
        }

        long[][] power(int p) {
            if (p == 1) return matrix;
            long[][] result = powers.get(p);
            if (result != null)
                return result;
            result = power(p / 2);
            powers.put(p / 2 * 2, result = multiply(result, result));
            if (p % 2 > 0)
                powers.put(p, result = multiply(result, power(p % 2)));
            return result;
        }

        private long[][] multiply(long[][] a, long[][] b) {
            long[][] m = new long[a.length][a.length];
            for (int i = 0; i < a.length; ++i) {
                for (int j = 0; j < a.length; ++j) {
                    long sum = 0;
                    for (int k = 0; k < a.length; ++k)
                        sum = (sum + a[i][k] * b[k][j]) % 1000000007L;
                    m[i][j] = sum;
                }
            }
            return m;
        }
    }
public class Solution {
    
    /*
     * Complete the countStrings function below.
     */
    static long countStrings(String r, int l) {
        return l == 0 ? 0 : new RegexCounter(new Regex(r)).count(l);
    }

    private static final Scanner scanner = new Scanner(System.in);

    public static void main(String[] args) throws IOException {
        BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(System.getenv("OUTPUT_PATH")));

        int t = Integer.parseInt(scanner.nextLine().trim());

        for (int tItr = 0; tItr < t; tItr++) {
            String[] rl = scanner.nextLine().split(" ");

            String r = rl[0];

            int l = Integer.parseInt(rl[1].trim());

            long result = countStrings(r, l);

            bufferedWriter.write(String.valueOf(result));
            bufferedWriter.newLine();
        }

        bufferedWriter.close();
    }
}

Count Strings JavaScript Solution

'use strict';

const fs = require('fs');

process.stdin.resume();
process.stdin.setEncoding('utf-8');

let inputString = '';
let currentLine = 0;

process.stdin.on('data', inputStdin => {
    inputString += inputStdin;
});

process.stdin.on('end', _ => {
    inputString = inputString.trim().split('\n').map(str => str.trim());

    main();
});

function readLine() {
    return inputString[currentLine++];
}

// import BigNumber from "../../environment/bignumber"

const BigNumber = require("bignumber.js")
const TerminalValue = {
    A : "a",
    B : "b"
}

const RegexOperator = {
    TERMINAL : "TERMINAL",
    OR : "OR",
    CONCAT : "CONCAT",
    REPEAT : "REPEAT"
}

const findOuterParenthesis = (text )  => {
    const parenthesis = []
    let currentParenthesis = {
        start : -1,
        end : -1
    }
    let parenthesisCounter = 0;

    for (var index in text ) {
        const letter = text[index] 
        if (letter == "(") {
            parenthesisCounter++
            if (currentParenthesis.start < 0) {
                currentParenthesis.start = parseInt(index)
            }
        }
        if (letter == ")") {
            parenthesisCounter--
            if (parenthesisCounter == 0 && currentParenthesis.start >= 0){
                currentParenthesis.end = parseInt(index)
            }
        }

        if (currentParenthesis.end >= 0) {
            parenthesis.push(currentParenthesis)
            currentParenthesis = {
                start : -1,
                end : -1
            }
        }
    }

    return parenthesis
}

const generateTree = (regex )  => {
    if ((regex == TerminalValue.A) || (regex == TerminalValue.B)) {
        return {
            type: RegexOperator.TERMINAL,
            value : regex
        }
    }

    const parenthesis = findOuterParenthesis(regex)

    
    const REPEAT_REGEX = /^\((.*)\*\)$/
    const matchRepeat = REPEAT_REGEX.exec(regex)
    if ((parenthesis.length==1) && matchRepeat){
        return {
            type: RegexOperator.REPEAT,
            children : [generateTree(matchRepeat[1])]
        }
    }
    
    if ((parenthesis.length == 1) && (parenthesis[0].start == 0) && (parenthesis[0].end == regex.length-1)) {
        return generateTree(regex.slice(1, regex.length-1))
    }
    
    if (parenthesis.length == 2) {
        const secondParenthesisStart = parenthesis[1].start
        if (regex[secondParenthesisStart-1] == "|") {
            return {
                type: RegexOperator.OR,
                children: [
                    generateTree(regex.slice(0, secondParenthesisStart-1)),
                    generateTree(regex.slice(secondParenthesisStart))
                ]
            }
        } else {
            return {
                type: RegexOperator.CONCAT,
                children: [
                    generateTree(regex.slice(0, secondParenthesisStart)),
                    generateTree(regex.slice(secondParenthesisStart))
                ]
            }
        }
    }
    if (parenthesis.length == 1) {
        const isParenthesisLeft = (parenthesis[0].start == 0) 
        let separatorIndex = isParenthesisLeft ?  (parenthesis[0].end + 1) : (parenthesis[0].start - 1)
        if (regex[separatorIndex] == "|") {
            return {
                type: RegexOperator.OR,
                children: [
                    generateTree(regex.slice(0, separatorIndex)),
                    generateTree(regex.slice(separatorIndex+1))
                ]
            }
        } else {
            separatorIndex = isParenthesisLeft ? separatorIndex : (separatorIndex + 1)
            return {
                type: RegexOperator.CONCAT,
                children: [
                    generateTree(regex.slice(0, separatorIndex)),
                    generateTree(regex.slice(separatorIndex))
                ]
            }
        }
    }

    const TERMINAL_CONCAT = /^([ab])([ab])$/
    const matchTerminalConcat = TERMINAL_CONCAT.exec(regex)
    if (matchTerminalConcat){
        return {
            type: RegexOperator.CONCAT,
            children : [
                generateTree(matchTerminalConcat[1]),
                generateTree(matchTerminalConcat[2])
            ]
        }
    }

    const TERMINAL_OR = /^([ab])\|([ab])$/
    const matchTerminalOr = TERMINAL_OR.exec(regex)
    if (matchTerminalOr){
        return {
            type: RegexOperator.OR,
            children : [
                generateTree(matchTerminalOr[1]),
                generateTree(matchTerminalOr[2])
            ]
        }
    }

    throw new Error ("Never")
}

const generateRegex = (tree ) => {
    if (tree.type == RegexOperator.REPEAT) {
        return `(${generateRegex(tree.children[0])}*)`
    }
    if (tree.type == RegexOperator.TERMINAL) {
        return tree.value
    }
    if (tree.type == RegexOperator.CONCAT) {
        return `(${generateRegex(tree.children[0])}${generateRegex(tree.children[1])})`
    }
    if (tree.type == RegexOperator.OR) {
        return `(${generateRegex(tree.children[0])}|${generateRegex(tree.children[1])})`
    }
}

const HUGE_PRIME = 1000000007

let i = 1
const getNewState = () => {
    return ""+i++;
}

const createNFALeaf = (letter )  => {
    const startState = getNewState()
    const endState = getNewState()
    return {
        s: startState,
        terminals: new Set([endState]),
        transitions: {
            [startState] : {
                a : new Set(),
                b : new Set(),
                [letter] : new Set([endState]),
                c : new Set()
            },
            [endState] : {
                a : new Set(),
                b : new Set(),
                c : new Set()
            }
        }
    }
}
const createNFALoop = (nfa) => {

    const newRootState = getNewState()
    const newRoot = {
        a : new Set(),
        b : new Set(),
        c : new Set([nfa.s])
    }
    nfa.transitions[newRootState] = newRoot
    nfa.terminals.add(newRootState)
    nfa.s = newRootState

    for (let terminal of nfa.terminals) {
        nfa.transitions[terminal].c.add(newRootState)
    }

    // for (let terminal of nfa.terminals) {
    //     nfa.transitions[terminal].c.add(nfa.s)
    // }

    // nfa.terminals.add(nfa.s)

    // nfa.transitions[nfa.s].c = new Set([...nfa.transitions[nfa.s].c, ...nfa.terminals])
    return nfa
}

const createNFAConcat = (nfaA , nfaB ) => {

    for (let terminal of nfaA.terminals) {
        nfaA.transitions[terminal].c.add(nfaB.s)
    }
    nfaA.transitions = {...nfaA.transitions, ...nfaB.transitions}
    nfaA.terminals = nfaB.terminals

    return nfaA
}

const createNFAOr = (nfaA, nfaB)  => {
    
    const newState = getNewState()

    return {
        s : newState,
        terminals: new Set([...nfaA.terminals, ...nfaB.terminals]),
        transitions : {
            ...nfaA.transitions,
            ...nfaB.transitions,
            [newState] : {
                a : new Set(),
                b : new Set(),
                c : new Set([nfaA.s, nfaB.s])
            }
        }
    }
}

const createNFA = (node )  => {
    if (node.type == RegexOperator.TERMINAL) {
        return createNFALeaf(node.value)
    }
    if (node.type == RegexOperator.REPEAT) {
        return createNFALoop(createNFA(node.children[0]))
    }
    if (node.type == RegexOperator.CONCAT) {
        return createNFAConcat(
                    createNFA(node.children[0]),
                    createNFA(node.children[1]),)
    }

    if (node.type == RegexOperator.OR) {
        return createNFAOr(
            createNFA(node.children[0]),
            createNFA(node.children[1]),)
    }
}

const printNFA = (nfa) => {
    console.log(`ROOT : ${nfa.s}`)
    console.log(`TERMINALS : ${[...nfa.terminals].join(" ")}`)
    for (var state in nfa.transitions) {
        console.log(`STATE : ${state}`)
        console.log(`A : ${[...nfa.transitions[state].a].join(" ")}`)
        console.log(`B : ${[...nfa.transitions[state].b].join(" ")}`)
        console.log(`C : ${[...nfa.transitions[state].c].join(" ")}`)
    }
}

const printDFA = (dfa )  => {
    console.log(`ROOT : ${dfa.s}`)
    console.log(`TERMINALS : ${[...dfa.terminals].join(" ")}`)
    for (var state in dfa.transitions) {
        console.log(`STATE : ${state}`)
        if (dfa.transitions[state].a) {
            console.log(`A : ${dfa.transitions[state].a}`)
        }
        if (dfa.transitions[state].b) {
            console.log(`B : ${dfa.transitions[state].b}`)
        }
    }
}
//Merge identical nodes
const minifyDFA = (dfa) => {
    const mergeMap  = {}
    const alreadyMerged = []
    
    for (var state in dfa.transitions) {
        if (alreadyMerged.includes(state)) {
            continue
        }
        alreadyMerged.push(state)

        for (var bState in dfa.transitions) {
            const isTransitionASame = (dfa.transitions[state].a == dfa.transitions[bState].a)
            const isTransitionBSame = (dfa.transitions[state].b == dfa.transitions[bState].b)
            const isTerminalSame = (dfa.terminals.has(state) && dfa.terminals.has(bState)) || (!dfa.terminals.has(state) && !dfa.terminals.has(bState))

            const isSameState = isTransitionASame && isTransitionBSame && isTerminalSame 
            if (isSameState) {
                alreadyMerged.push(bState)
                mergeMap[bState] = state
            }
        }
    }

    for (var state in dfa.transitions) {

        if (dfa.transitions[state].a) {
            dfa.transitions[state].a = mergeMap[dfa.transitions[state].a]
        }
        if (dfa.transitions[state].b) {
            dfa.transitions[state].b = mergeMap[dfa.transitions[state].b]
        }

        const newState = mergeMap[state]
        if (newState != state) {
            dfa.transitions[newState] = dfa.transitions[state]
            delete dfa.transitions[state]
        }

        // console.log({newState})
        // console.log(dfa.transitions[newState])
    }

    dfa.s = mergeMap[dfa.s]
    dfa.terminals = new Set([...dfa.terminals].map(s => mergeMap[s]))

    return dfa
}

const encodeStatesSet = (states) => {
    const sortedStates = [...states]
    sortedStates.sort()
    return sortedStates.join("_")
}

const decodeStatesSet = (states) => {
    return states.split("_").filter(s => s.length)
}

const NFAtoDFA = (nfa) => {

    const dfaStartState = encodeStatesSet(new Set(getClousure(nfa, nfa.s)))

    const dfa  = {
        s : dfaStartState,
        transitions: {},
        terminals : new Set()
    }

    const statesQueue = [dfaStartState]
    while (statesQueue.length > 0) {
        const cState = statesQueue.shift()

        if (cState == "") {
            continue
        }

        const cStateSet = decodeStatesSet(cState)
        let reachableA = getReachable(nfa, [...cStateSet], "a")
        const keyA = encodeStatesSet(reachableA)
        
        let reachableB = getReachable(nfa, [...cStateSet], "b")
        const keyB = encodeStatesSet(reachableB)

        if (dfa.transitions[keyA] == undefined) {
            statesQueue.push(keyA)
        }
        if (dfa.transitions[keyB] == undefined) {
            statesQueue.push(keyB)
        }

        dfa.transitions[cState] = {
            a : keyA,
            b : keyB
        }
    }

    for (var state in dfa.transitions) {
        const stateSet = decodeStatesSet(state)
        for (var rawState of stateSet) {
            if (nfa.terminals.has(rawState)) {
                dfa.terminals.add(state)
            }
        }
    }

    return dfa
}

const DFAMapIndex = (dfa) => {
    let index = 0;
    let indexMap  = {}
    for (var state in dfa.transitions) {
        if (indexMap[state] == undefined) {
            indexMap[state] = index++
        }
    }

    return indexMap
}

const getClousure = (nfa, state ) => {
    const eClousure = [state]
    let i = 0
    while (i < eClousure.length) {
        const cState = eClousure[i]
        for (var adjacency of nfa.transitions[cState].c) {
            if (eClousure.includes(adjacency) == false) {
                eClousure.push(adjacency)
            }
        }
        i++
    }

    return eClousure
}

const getReachable = (nfa, states , letter ) => {
    const reachableStates = []
    for (let cState of states) {
        for (var adjacency of nfa.transitions[cState][letter]) {
            if (reachableStates.includes(adjacency) == false) {
                reachableStates.push(adjacency)
            }
        }
    }

    let reachableClousure = new Set()
    for (var state of reachableStates) {
        const cClousure = getClousure(nfa, state)
        reachableClousure = new Set([...reachableClousure, ...cClousure])
    }

    return reachableClousure
}

const createWalkMatrix = (dfa ) => {
    const size = Object.keys(dfa.transitions).length
    const walkMatrix = Array(size).fill(null).map(() => Array(size).fill(0))
    for (var state in dfa.transitions) {
        const srcIndex = state
        if (dfa.transitions[state].a) {
            const aIndex = parseInt(dfa.transitions[state].a)
            if (isNaN(aIndex) == false) {
                walkMatrix[srcIndex][aIndex]++
            }
        }

        if (dfa.transitions[state].b) {
            const bIndex = parseInt(dfa.transitions[state].b)
            if (isNaN(bIndex) == false) {
                walkMatrix[srcIndex][bIndex]++
            }
        }
    }

    return walkMatrix
}
const multiplyMatrices = (A , B ) => {
    const size = A.length
    const result = Array(size).fill(null).map(() => Array(size).fill(0))

    for (var i = 0; i < size; i++) {
        for (var j = 0; j < size; j++) {
            let cellValue = new BigNumber(0)
            for (var k = 0; k < size; k++) {
                cellValue = cellValue.plus(new BigNumber(A[i][k]).times(new BigNumber(B[k][j])))
            }
            cellValue = cellValue.mod(HUGE_PRIME)
            
            result[i][j] = cellValue.toNumber()
        }
    }
    return result
}

const matrixPower = (matrix , power )   => {

    if (power == 1) {
        return matrix
    }
    
    let halfPower = Math.floor(power/2)
    let halfMatrix = matrixPower(matrix, halfPower)
    
    let halfMatrixSquared = multiplyMatrices(halfMatrix, halfMatrix)
    
    let result = (power % 2) ? multiplyMatrices(halfMatrixSquared, matrix) : halfMatrixSquared
    return result
}

const numberOfPaths = (dfa, paths) => {
    const startIndex = dfa.s
    let result = 0
    for (var terminalIndex of dfa.terminals) {
        result += paths[startIndex][terminalIndex]
        result %= HUGE_PRIME
    }

    return result
}

const prettifyDFA = (dfa) => {
    const indexMap = DFAMapIndex(dfa)
    const prettyDFA = {
        s : ""+indexMap[dfa.s], 
        terminals : new Set([...dfa.terminals].map(uglyState => ""+indexMap[uglyState])),
        transitions : {}
    }

    for (var uglyState in dfa.transitions) {
        const prettyState = indexMap[uglyState]
        prettyDFA.transitions[prettyState] = {
        }

        if (indexMap[dfa.transitions[uglyState].a] !== undefined) {
            prettyDFA.transitions[prettyState].a= ""+indexMap[dfa.transitions[uglyState].a]
        }
        if (indexMap[dfa.transitions[uglyState].b] !== undefined) {
            prettyDFA.transitions[prettyState].b = ""+indexMap[dfa.transitions[uglyState].b]
        }
    }
    return prettyDFA
}

const countStrings = (regex, L) => {
    const tree = generateTree(regex)
    const nfa = createNFA(tree)
    let dfa = NFAtoDFA(nfa)
    dfa = minifyDFA(dfa)
    dfa = prettifyDFA(dfa)
    const walkMatrix = createWalkMatrix(dfa)
    const pathMatrix = matrixPower(walkMatrix, L)
    return numberOfPaths(dfa, pathMatrix)
}


function main() {
    const ws = fs.createWriteStream(process.env.OUTPUT_PATH);

    const t = parseInt(readLine(), 10);

    for (let tItr = 0; tItr < t; tItr++) {
        const rl = readLine().split(' ');

        const r = rl[0];

        const l = parseInt(rl[1], 10);

        let result = countStrings(r, l);

        ws.write(result + "\n");
    }

    ws.end();
}

Count Strings Python Solution

from enum import Enum
from collections import namedtuple

Edge = namedtuple('Edge', 'dest char')

class Alphabet(Enum):
    a = 'a'
    b = 'b'
    e = None


def empty_edge(dest):
    return Edge(dest, Alphabet.e)


class CountStrings:
    def __init__(self, regex_string):
        RegexGraphNFA.node_count = 0
        self.regex_string = regex_string
        nfa_graph = self.translate_regex()
        translate_graph = TranslateGraph(nfa_graph)
        self.dfa_graph = translate_graph.translate()

    def calculate(self, string_length):
        return self.dfa_graph.count_paths(string_length)

    def translate_regex(self, index=0):
        result_set = ResultSet()
        while index < len(self.regex_string):
            if self.regex_string[index] == '(':
                out_list, index = self.translate_regex(index + 1)
                result_set.insert(out_list)
            elif self.regex_string[index] == ')':
                result = result_set.calculate_result()
                return result, index
            elif self.regex_string[index] == '|':
                result_set.set_or()
            elif self.regex_string[index] == '*':
                result_set.set_repeat()
            else:
                result_set.insert(RegexGraphNFA(Alphabet[self.regex_string[index]]))
            index += 1
        return result_set.calculate_result()


class ResultSet:
    AND, OR, REPEAT = 1, 2, 3

    def __init__(self):
        self.r1 = None
        self.r2 = None
        self.op = self.AND

    def set_or(self):
        self.op = self.OR

    def set_repeat(self):
        self.op = self.REPEAT

    def calculate_result(self):
        if self.op == self.REPEAT:
            self.calculate_repeat()
        elif self.r2 is None:
            pass
        elif self.op == self.OR:
            self.calculate_or()
        else:
            self.calculate_and()
        return self.r1

    def calculate_repeat(self):
        self.r1.graph_repeat()

    def calculate_or(self):
        self.r1.graph_or(self.r2)

    def calculate_and(self):
        self.r1.graph_add(self.r2)

    def insert(self, value):
        if self.r1 is None:
            self.r1 = value
        else:
            self.r2 = value


class RegexGraphNFA:
    node_count = 0

    def __init__(self, in_char):
        self.edges = None
        self.head = None
        self.tail = None
        self.insert_char(in_char)

    @classmethod
    def get_next_node_id(cls):
        node_id = cls.node_count
        cls.node_count += 1
        return node_id

    def insert_char(self, value):
        self.head = self.get_next_node_id()
        self.tail = self.get_next_node_id()
        self.edges = {self.head: [Edge(self.tail, value)],
                      self.tail: []}

    def graph_add(self, other):
        join_node = self.get_next_node_id()
        self.join(other)
        self.edges[self.tail].append(empty_edge(join_node))
        self.edges[join_node] = [empty_edge(other.head)]
        self.tail = other.tail

    def graph_repeat(self):
        new_head = self.get_next_node_id()
        new_tail = self.get_next_node_id()
        self.edges[self.tail].extend([empty_edge(self.head), empty_edge(new_tail)])
        self.edges[new_head] = [empty_edge(self.head), empty_edge(new_tail)]
        self.edges[new_tail] = []
        self.head = new_head
        self.tail = new_tail

    def graph_or(self, other):
        new_head = self.get_next_node_id()
        new_tail = self.get_next_node_id()
        self.join(other)
        self.edges[new_head] = [empty_edge(self.head), empty_edge(other.head)]
        self.edges[self.tail].append(empty_edge(new_tail))
        self.edges[other.tail].append(empty_edge(new_tail))
        self.edges[new_tail] = []
        self.head = new_head
        self.tail = new_tail

    def join(self, other):
        for node, edge in other.edges.items():
            if node in self.edges:
                self.edges[node].extend(edge)
            else:
                self.edges[node] = edge

    def get_dfa_char_node_set(self, origin, use_char):
        node_set = set()
        for my_node in origin:
            for edges in self.edges[my_node]:
                if edges.char == use_char:
                    node_set.add(edges.dest)

        return self.get_dfa_zero_node_set(node_set)

    def get_dfa_zero_node_set(self, origin):
        node_set = set(origin)
        processed = set()
        while len(node_set.difference(processed)) > 0:
            my_node = node_set.difference(processed).pop()
            for edges in self.edges[my_node]:
                if edges.char == Alphabet.e:
                    node_set.add(edges.dest)
            processed.add(my_node)
        return frozenset(node_set)


class TranslateGraph:
    language = (Alphabet.a, Alphabet.b)

    def __init__(self, nfa_graph: RegexGraphNFA):
        self.node_count = 0
        self.nfa_graph = nfa_graph
        self.trans_to = {}
        self.trans_from = {}
        self.table = {}

    def get_next_node_id(self):
        node_id = self.node_count
        self.node_count += 1
        return node_id

    def add_translate(self, nfa_ids):
        if len(nfa_ids) == 0:
            return None
        if nfa_ids not in self.trans_from:
            dfa_id = self.get_next_node_id()
            self.trans_to[dfa_id] = nfa_ids
            self.trans_from[nfa_ids] = dfa_id
            self.table[dfa_id] = dict(zip(self.language, [None] * len(self.language)))
        return self.trans_from[nfa_ids]

    def translate(self):
        self.create_translate_table()
        return self.build_dfa()

    def build_dfa(self):
        head = 0
        valid_ends = set()
        adjacency = {}
        for node, edges in self.table.items():
            adjacency[node] = []
            if self.nfa_graph.tail in self.trans_to[node]:
                valid_ends.add(node)
            for my_char, node_dest in edges.items():
                if node_dest is not None:
                    adjacency[node].append(Edge(node_dest, my_char))
        return RegexGraphDFA(head, valid_ends, adjacency)

    def create_translate_table(self):
        nfa_ids = self.nfa_graph.get_dfa_zero_node_set({self.nfa_graph.head})
        self.add_translate(nfa_ids)
        processed = set()

        while len(set(self.table).difference(processed)) > 0:
            my_node = set(self.table).difference(processed).pop()
            for char in self.language:
                next_nodes = self.nfa_graph.get_dfa_char_node_set(self.trans_to[my_node], char)
                dfa_id = self.add_translate(next_nodes)
                self.table[my_node][char] = dfa_id
            processed.add(my_node)


class RegexGraphDFA:
    def __init__(self, head, valid_ends, edges):
        self.edges = edges
        self.head = head
        self.valid_ends = valid_ends
        self.edge_matrix = Matrix.get_from_edges(len(self.edges), self.edges)

    def count_paths(self, length):
        modulo = 1000000007
        if length == 0:
            return 0 if 0 not in self.valid_ends else 1
        edge_walk = self.edge_matrix.pow(length, modulo)
        count = 0
        for end_node in self.valid_ends:
            count += edge_walk.matrix[self.head][end_node]
        return count % modulo


class Matrix:
    @staticmethod
    def get_from_edges(dimension, adj_list):
        my_matrix = Matrix.get_zeros(dimension)
        my_matrix.add_edges(adj_list)
        return my_matrix

    @staticmethod
    def get_zeros(dimension):
        my_matrix = Matrix(dimension)
        my_matrix.pad_zeros()
        return my_matrix

    def copy(self):
        my_matrix = Matrix(self.dimension)
        my_matrix.matrix = []
        for i in range(self.dimension):
            my_matrix.matrix.append([])
            for j in range(self.dimension):
                my_matrix.matrix[i].append(self.matrix[i][j])
        return my_matrix

    def __init__(self, dimension):
        self.matrix = None
        self.dimension = dimension

    def __str__(self):
        my_str = ''
        for row in self.matrix:
            my_str += str(row) + "\n"
        return my_str

    def pad_zeros(self):
        self.matrix = []
        for i in range(self.dimension):
            self.matrix.append([])
            for j in range(self.dimension):
                self.matrix[i].append(0)

    def add_edges(self, adj_list):
        if adj_list is not None:
            for from_node, edge_list in adj_list.items():
                for to_node, my_char in edge_list:
                    self.matrix[from_node][to_node] = 1

    def pow(self, pow_val, mod_val=None):
        started = False
        current_pow = 1
        current_val = 0
        while pow_val > 0:
            if current_pow == 1:
                current_pow_matrix = self.copy()
            else:
                current_pow_matrix = current_pow_matrix.mat_square_mult(current_pow_matrix, mod_val)
            if pow_val % (2 * current_pow):
                current_val += current_pow
                if started:
                    result = result.mat_square_mult(current_pow_matrix, mod_val)
                else:
                    result = current_pow_matrix.copy()
                    started = True
                pow_val -= current_pow
            current_pow *= 2
        return result

    def mat_square_mult(self, other, mod_val=None):
        result = Matrix.get_zeros(self.dimension)
        for i in range(self.dimension):
            for j in range(self.dimension):
                val = 0
                for k in range(self.dimension):
                    val += self.matrix[i][k] * other.matrix[k][j]
                if mod_val is not None:
                    val %= mod_val
                result.matrix[i][j] = val

        return result


def main():
    cases = int(input().strip())
    for i in range(cases):
        in_line = input().strip().split()
        my_class = CountStrings(in_line[0])
        print(my_class.calculate(int(in_line[1])))


if __name__ == "__main__":
    main()

other Solutions

  • HackerRank String Function Calculation Solution
  • HackerRank Build a Palindrome Problem Solution
c C# C++ HackerRank Solutions java javascript python CcppCSharpHackerrank Solutionsjavajavascriptpython

Post navigation

Previous post
Next post

Leave a Reply

You must be logged in to post a comment.

  • HackerRank Dynamic Array Problem Solution
  • HackerRank 2D Array – DS Problem Solution
  • Hackerrank Array – DS Problem Solution
  • Von Neumann and Harvard Machine Architecture
  • Development of Computers
©2025 THECSICENCE | WordPress Theme by SuperbThemes