Count Strings


Problem Statement :


A regular expression is used to describe a set of strings. For this problem the alphabet is limited to 'a' and 'b'.

We define  to be a valid regular expression if:
1)  is "" or "".
2)  is of the form "", where  and  are regular expressions.
3)  is of the form "" where  and  are regular expressions.
4)  is of the form "" where  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; '' is invalid.

The set of strings recognized by  are as follows:
1) If  is "", then the set of strings recognized .
2) If  is "", then the set of strings recognized .
3) If  is of the form "" then the set of strings recognized = all strings which can be obtained by a concatenation of strings  and , where  is recognized by  and  by .
4) If  is of the form "" then the set of strings recognized = union of the set of strings recognized by  and .
5) If  is of the form "" then the the strings recognized are the empty string and the concatenation of an arbitrary number of copies of any string recognized by .

Task
Given a regular expression and an integer, , count how many strings of length  are recognized by it.

Input Format

The first line contains the number of test cases .  test cases follow.
Each test case contains a regular expression, , and an integer, .



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^9 + 7.



Solution :



title-img


                            Solution in C :

In   C++  :








#include<stdio.h>
#include<vector>
#include<set>
#include<stdlib.h>
#include<map>
#include<string.h>
#include<iostream>
using namespace std ;
typedef pair<int,int> P ;
#define INF (int)1e9
#define MOD 1000000007
#define MAXN 102
int n,out[MAXN],g[MAXN][MAXN] ;
int ga[MAXN][MAXN],gb[MAXN][MAXN] ;
int g2[MAXN][MAXN] ;
set<int> aMask[MAXN],bMask[MAXN] ;

P construct(char regex[],int low,int high)
{
  int start = n++ ;
  int end = n++ ;
  if(low == high)
  {
    out[start] = regex[low] - 'a' ;
    return P(start,end) ;
  }
  int mid,ct = 0 ;
  for(mid = low + 1;mid <= high;mid++)
  {
    if(regex[mid] == '(') ct++ ;
    if(regex[mid] == ')') ct-- ;
    if(ct == 0) break ;
  }

  P ret1 = construct(regex,low + 1,mid) ;
  if(regex[mid + 1] == '|')
  {
    P ret2 = construct(regex,mid + 2,high - 1) ;
    g[start][ret1.first] = g[start][ret2.first] = 1 ;
    g[ret1.second][end] = g[ret2.second][end] = 1 ;
  }
  else if(regex[mid + 1] == '*')
  {
    g[start][ret1.first] = g[start][end] = 1 ;
    g[ret1.second][end] = g[end][start] = 1 ;
  }
  else
  {
    P ret2 = construct(regex,mid + 1,high - 1) ;
    g[start][ret1.first] = g[ret1.second][ret2.first] = 1 ;
    g[ret2.second][end] = 1 ;
  }
  return P(start,end) ;
}

void mul(int a[MAXN][MAXN],int b[MAXN][MAXN],int c[MAXN][MAXN],int N)
{
  int d[MAXN][MAXN] ;
  for(int i = 0;i < N;i++)
    for(int j = 0;j < N;j++)
      d[i][j] = 0 ;
  for(int k = 0;k < N;k++)
    for(int i = 0;i < N;i++)
      for(int j = 0;j < N;j++)
        d[i][j] = (d[i][j] + 1LL * a[i][k] * b[k][j]) % MOD ;
  for(int i = 0;i < N;i++)
    for(int j = 0;j < N;j++)
      c[i][j] = d[i][j] ;
}


void power(int a[MAXN][MAXN],int b[MAXN][MAXN],int k,int N)
{
  if(k == 0)
  {
    for(int i = 0;i < N;i++)
      for(int j = 0;j < N;j++)
        b[i][j] = i == j ? 1 : 0 ;
    return ;
  }
  int c[MAXN][MAXN] ;
  power(a,c,k / 2,N) ;
  mul(c,c,b,N) ;
  if(k % 2 == 1)
  {
    mul(a,b,b,N) ;
  }
}

int solve(char * regex,int L)
{
  n = 0 ;
  memset(g,0,sizeof g) ;
  memset(out,255,sizeof out) ;

  P nfa = construct(regex,0,strlen(regex) - 1) ;

  for(int i = 0;i < n;i++) g[i][i] = 1 ;
  for(int k = 0;k < n;k++)
    for(int i = 0;i < n;i++)
      for(int j = 0;j < n;j++)
        if(g[i][k] && g[k][j])
          g[i][j] = 1 ;

  memset(ga,0,sizeof ga) ;
  memset(gb,0,sizeof gb) ;
  for(int i = 0;i < MAXN;i++) aMask[i].clear(),bMask[i].clear() ;
  for(int i = 0;i < n;i++)
    for(int j = 0;j < n;j++)
    {
      bool va = false,vb = false ;
      for(int k = 0;k + 1 < n;k++)
      {
        if(g[i][k] && out[k] != -1 && g[k + 1][j])
        {
          if(out[k] == 0) va = true ;
          else vb = true ;
        }
      }
      if(va) ga[i][j] = true ;
      if(vb) gb[i][j] = true ;
      if(ga[i][j]) aMask[i].insert(j) ;
      if(gb[i][j]) bMask[i].insert(j) ;
    }

  memset(g2,0,sizeof g2) ;
  int id = 0 ;
  set<int> orig[MAXN],q[MAXN] ;
  int sz = 0 ;
  map<set<int>,int> mp ;

  set<int> start ;
  start.insert(nfa.first) ;
  q[sz++] = start ;
  mp[start] = id++ ;
  orig[id - 1] = start ;

  for(int i = 0;i < sz;i++)
  {
    set<int> k = q[i] ;
    int kk = mp[k] ;

    set<int> a,b ;
    for(int j = 0;j < n;j++)
      if(k.find(j) != k.end())
      {
        for(set<int> :: iterator it = aMask[j].begin();it != aMask[j].end();++it) a.insert(*it) ;
        for(set<int> :: iterator it = bMask[j].begin();it != bMask[j].end();++it) b.insert(*it) ;
      }

    if(!mp.count(a))
    {
      q[sz++] = a ;
      mp[a] = id++ ;
      orig[id - 1] = a ;
    }
    g2[kk][mp[a]]++ ;

    if(!mp.count(b))
    {
      q[sz++] = b ;
      mp[b] = id++ ;
      orig[id - 1] = b ;
    }
    g2[kk][mp[b]]++ ;
  }
  // cout << "nodes: " << n << ", " << id << endl ;

  int g3[MAXN][MAXN] ;
  power(g2,g3,L,id) ;
  int ret = 0 ;
  for(int i = 0;i < id;i++)
    if(orig[i].find(nfa.second) != orig[i].end())
      ret = (ret + g3[mp[start]][i]) % MOD ;
  return ret ;
}

bool vis[MAXN][MAXN] ;
int _L ;
int cur[MAXN] ;

void dfs(int k,int p)
{
  if(vis[k][p]) return ;
  vis[k][p] = true ;
  for(int i = 0;i < n;i++)
    if(g[k][i])
      dfs(i,p) ;
  if(out[k] != -1 && p < _L && cur[p] == out[k]) dfs(k + 1,p + 1) ;
}

int check()
{
  memset(vis,false,sizeof vis) ;
  dfs(0,0) ;
  return vis[1][_L] ? 1 : 0 ;
}

int generate(int k)
{
  if(k == _L) return check() ;
  cur[k] = 0 ;
  int ret = generate(k + 1) ;
  cur[k] = 1 ;
  ret += generate(k + 1) ;
  return ret ;
}

int solve2(char * regex,int L)
{
  _L = L ;
  n = 0 ;
  memset(g,0,sizeof g) ;
  memset(out,255,sizeof out) ;
  P nfa = construct(regex,0,strlen(regex) - 1) ;
  return generate(0) ;
}

string genRegex(int k)
{
  if(k == 1)
  {
    string s ;
    if(rand() % 2 == 0) s.push_back('a') ;
    else s.push_back('b') ;
    return s ;
  }

  string s ; 
  int x = rand() % 3 ;
  if(x == 0)
  {
    s = genRegex(k - 1) ;
    s = "(" + s + "*)" ;
  }
  else
  {
    int f = 1 + rand()  % (k - 1) ;
    int se = k - f ;
    string s1 = genRegex(f) ;
    string s2 = genRegex(se) ;
    if(x == 1) s = "(" + s1 + s2 + ")" ;
    else s = "(" + s1 + "|" + s2 + ")" ;
  }
  return s ; 
}

void generate2()
{
  char in[10] = "in .txt" ;
  for(int test = 1;test < 10;test++)
  {
    in[2] = test + '0' ;
    FILE * fout = fopen(in,"w") ;

    int runs = 50 ;

    fprintf(fout,"%d\n",runs) ;
    for(int t = 0;t < runs;t++)
    {
      int k = 28 - rand() % 10 ;
      string s = genRegex(k) ;
      if(s.size() > 100) while(1) ;
      int L = rand() % 1000000000 + 1 ;
      fprintf(fout,"%s %d\n",s.c_str(),L) ;
    }
  }
}

void test()
{
  for(int t = 0;t < 100;t++)
  {
    string s = genRegex(15) ;
    cout << s << endl ;
    int L = rand() % 12 + 5 ;
    char reg[MAXN] = {} ;
    for(int i = 0;i < s.size();i++) reg[i] = s[i] ;
    int ret1 = solve(reg,L) ;
    int ret2 = solve2(reg,L) ;
    cout << ret1 << " " << ret2 << endl ;
    if(ret1 != ret2)
    {
      cout << "Failed on: " << s << endl ;
      while(1) ;
    }
  }
}

int pow2(int k)
{
  if(k == 0) return 1 ;
  int ret = pow2(k / 2) ;
  ret = 1LL * ret * ret % MOD ;
  if(k & 1) ret = 1LL * ret * 2 % MOD ;
  return ret ;
}

int main()
{
  // generate2() ; return 0 ;
  // test() ; return 0 ;

  int runs ;
  scanf("%d",&runs) ;
  for(int t = 1;t <= runs;t++)
  {
    int L ;
    char regex[MAXN] ;
    scanf("%s%d",regex,&L) ;

    int ret = solve(regex,L) ;

    //  cout << "test: " << t << endl ;
    //  cout << ret << " " << pow2(L) << endl ; continue ;

    /*
       int ret2 = solve2(regex,L) ;  
       cout << ret << " " << ret2 << endl ;
       if(ret != ret2)
       {
       cout << "Failed" << endl ;
       while(1) ;
       }
       */

    printf("%d\n",ret) ;
  }
  return 0 ;
}









In   Java  :









import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Scanner;
import java.util.Stack;

public class Solution {
 
 static int parseIndex = 0;
 static final int MOD = 1000000007;
 
 public static void main(String[] args) {
  Scanner scan = new Scanner(System.in);
  int cases = scan.nextInt();
  for(int cs=0; cs<cases; cs++){
   String regex = scan.next();
   int length = scan.nextInt();
   NFA nfa = parse(regex);
   DFA dfa = new DFA(nfa);
   long[][] graph = dfa.toAdjacencyMatrix();
   graph = power(graph, length);
   long words = 0;
   for(int end : dfa.ends){
    words += graph[dfa.start][end];
   }
   words %= MOD;
   System.out.println(words);
  }
 }
 
 static long[][] power(long[][] matrix, long power){
  if(power == 1)
   return matrix;
  else if(power % 2 == 0)
   return power(multiply(matrix, matrix), power/2);
  else
   return multiply(matrix, power(multiply(matrix, matrix), power/2));
 }
 
 static long[][] multiply(long[][] m1, long[][] m2){
  long[][] res = new long[m1.length][m1.length];
  for(int i=0; i<m1.length; i++){
   for(int j=0; j<m1.length; j++){
    long dotProd = 0;
    for(int k=0; k<m1.length; k++){
     dotProd += m1[i][k] * m2[k][j];
                    dotProd %= MOD;
    }
    res[i][j] = dotProd;
   }
  }
  return res;
 }
 
 static NFA parse(String regex){
  parseIndex = 0;
  return new NFA(regex);
 }
 
 static class DFA{
  int start;
  HashSet<Integer> ends = new HashSet<Integer>();
  List<DFANode> nodes = new ArrayList<DFANode>();
  HashMap<DFANode, Integer> nodeMap = new HashMap<DFANode, Integer>();
  
  public DFA(NFA nfa){
   HashSet<DFANode> allNodes = new HashSet<DFANode>();
   Queue<DFANode> wipNodes = new LinkedList<DFANode>();
   DFANode startNode = new DFANode(nfa.start.findClosure());
   startNode.startState = true;
   allNodes.add(startNode);
   wipNodes.offer(startNode);
   
   while(!wipNodes.isEmpty()){
    DFANode node = wipNodes.poll();
    
    HashSet<NFANode> nextState = NFA.nextState(node.state, 'a');
    if(!nextState.isEmpty()){
     DFANode next = new DFANode(nextState);
     node.letterA = next;
     if(allNodes.add(next))
      wipNodes.offer(next);
    }
    
    nextState = NFA.nextState(node.state, 'b');
    if(!nextState.isEmpty()){
     DFANode next = new DFANode(nextState);
     node.letterB = next;
     if(allNodes.add(next))
      wipNodes.offer(next);
    }
    
    if(node.state.contains(nfa.end))
     node.endState = true;
   }
   
   for(DFANode node : allNodes){
    int index = nodes.size();
    nodes.add(node);
    nodeMap.put(node, index);
    if(node.startState)
     start = index;
    else if(node.endState)
     ends.add(index);
   }
  }
  
  long[][] toAdjacencyMatrix(){
   long[][] matrix = new long[nodes.size()][nodes.size()];
   for(int i=0; i<nodes.size(); i++){
    DFANode node = nodes.get(i);
    if(node.letterA != null)
     matrix[i][nodeMap.get(node.letterA)] = 1;
    if(node.letterB != null)
     matrix[i][nodeMap.get(node.letterB)] = 1;
   }
   return matrix;
  }
 }
 
 static class NFA{
  NFANode start, end;
  
  public NFA(String regex){
   start = new NFANode();
   end = new NFANode();
   end.endState = true;
   
   if(regex.charAt(parseIndex) == 'a'){//direct 'a' transition
    parseIndex++;
    start.letterA.add(end);
   } else if(regex.charAt(parseIndex) == 'b'){//direction 'b' transition
    parseIndex++;
    start.letterB.add(end);
   } else{//opening bracket
    parseIndex++;
    NFA child = new NFA(regex);
    if(regex.charAt(parseIndex) == '*'){//repeat
     parseIndex++;
     start.epsilon.add(child.start);
     start.epsilon.add(end);
     child.end.epsilon.add(end);
     child.end.endState = false;
     end.epsilon.add(child.start);
    } else if(regex.charAt(parseIndex) == '|'){//or
     parseIndex++;
     NFA child2 = new NFA(regex);
     start.epsilon.add(child.start);
     start.epsilon.add(child2.start);
     child.end.epsilon.add(end);
     child2.end.epsilon.add(end);
     child.end.endState = false;
     child2.end.endState = false;
    } else{//concat
     NFA child2 = new NFA(regex);
     start = child.start;
     end = child2.end;
     child.end.epsilon.add(child2.start);
     child.end.endState = false;
    }
    parseIndex++;//skip closing bracket
   }
  }
  
  static HashSet<NFANode> nextState(HashSet<NFANode> states, char transition){
   HashSet<NFANode> reachableClosure = new HashSet<NFANode>();
   for(NFANode node : states){
    HashSet<NFANode> reachable = new HashSet<NFANode>();
    switch(transition){
    case 'a':
     reachable.addAll(node.letterA);
     break;
    case 'b':
     reachable.addAll(node.letterB);
     break;
    }
    for(NFANode n : reachable)
     reachableClosure.addAll(n.findClosure());
   }
   return reachableClosure;
  }
 }
 
 static class NFANode{
  HashSet<NFANode> letterA = new HashSet<NFANode>();
  HashSet<NFANode> letterB = new HashSet<NFANode>();
  HashSet<NFANode> epsilon = new HashSet<NFANode>();
  
  boolean endState = false;
  
  HashSet<NFANode> findClosure(){
   HashSet<NFANode> closure = new HashSet<NFANode>();
   Stack<NFANode> DFS = new Stack<NFANode>();
   DFS.push(this);
   while(!DFS.isEmpty()){
    NFANode node = DFS.pop();
    closure.add(node);
    for(NFANode n : node.epsilon)
                    if(!closure.contains(n))
         DFS.push(n);
   }
   return closure;
  }
 }
 
 static class DFANode{
  DFANode letterA;
  DFANode letterB;
  
  HashSet<NFANode> state = new HashSet<NFANode>();
  
  boolean startState = false;
  boolean endState = false;
  
  public DFANode(HashSet<NFANode> state){
   this.state = state;
  }

  @Override
  public int hashCode() {
   final int prime = 31;
   int result = 1;
   result = prime * result + ((state == null) ? 0 : state.hashCode());
   return result;
  }

  @Override
  public boolean equals(Object obj) {
   if (this == obj)
    return true;
   if (obj == null)
    return false;
   if (getClass() != obj.getClass())
    return false;
   DFANode other = (DFANode) obj;
   if (state == null) {
    if (other.state != null)
     return false;
   } else if (!state.equals(other.state))
    return false;
   return true;
  }
 }
}










In   Python3 :








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()
            else:
                result_set.insert(self.regex_string[index])
            index += 1
        return result_set.calculate_result()


class ResultSet:
    def __init__(self):
        self.r1 = None
        self.r2 = None
        self.has_or = False

    def set_or(self):
        self.has_or = True

    def calculate_result(self):
        repeat = True if self.r2 == '*' else False
        if self.r2 is None:
            pass
        elif repeat:
            self.calculate_repeat()
        elif self.has_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 value != '*' and isinstance(value, str):
            value = RegexGraphNFA.get_char_graph(Alphabet[value])
        if self.r1 is None:
            self.r1 = value
        else:
            self.r2 = value


class RegexGraphNFA:
    node_count = 0

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

    @staticmethod
    def get_char_graph(value):
        my_graph = RegexGraphNFA()
        my_graph.insert_char(value)
        return my_graph

    @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
        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
        target = pow_val
        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
                # print(current_pow, current_val, target)
                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()
                        








View More Similar Problems

Cube Summation

You are given a 3-D Matrix in which each block contains 0 initially. The first block is defined by the coordinate (1,1,1) and the last block is defined by the coordinate (N,N,N). There are two types of queries. UPDATE x y z W updates the value of block (x,y,z) to W. QUERY x1 y1 z1 x2 y2 z2 calculates the sum of the value of blocks whose x coordinate is between x1 and x2 (inclusive), y coor

View Solution →

Direct Connections

Enter-View ( EV ) is a linear, street-like country. By linear, we mean all the cities of the country are placed on a single straight line - the x -axis. Thus every city's position can be defined by a single coordinate, xi, the distance from the left borderline of the country. You can treat all cities as single points. Unfortunately, the dictator of telecommunication of EV (Mr. S. Treat Jr.) do

View Solution →

Subsequence Weighting

A subsequence of a sequence is a sequence which is obtained by deleting zero or more elements from the sequence. You are given a sequence A in which every element is a pair of integers i.e A = [(a1, w1), (a2, w2),..., (aN, wN)]. For a subseqence B = [(b1, v1), (b2, v2), ...., (bM, vM)] of the given sequence : We call it increasing if for every i (1 <= i < M ) , bi < bi+1. Weight(B) =

View Solution →

Kindergarten Adventures

Meera teaches a class of n students, and every day in her classroom is an adventure. Today is drawing day! The students are sitting around a round table, and they are numbered from 1 to n in the clockwise direction. This means that the students are numbered 1, 2, 3, . . . , n-1, n, and students 1 and n are sitting next to each other. After letting the students draw for a certain period of ti

View Solution →

Mr. X and His Shots

A cricket match is going to be held. The field is represented by a 1D plane. A cricketer, Mr. X has N favorite shots. Each shot has a particular range. The range of the ith shot is from Ai to Bi. That means his favorite shot can be anywhere in this range. Each player on the opposite team can field only in a particular range. Player i can field from Ci to Di. You are given the N favorite shots of M

View Solution →

Jim and the Skyscrapers

Jim has invented a new flying object called HZ42. HZ42 is like a broom and can only fly horizontally, independent of the environment. One day, Jim started his flight from Dubai's highest skyscraper, traveled some distance and landed on another skyscraper of same height! So much fun! But unfortunately, new skyscrapers have been built recently. Let us describe the problem in one dimensional space

View Solution →