Monday, April 16, 2012

TopCoder Open 2012 - Round 1C

Level One - PasswordXGrid


Source Code
1:  long long PasswordXGuessing::howMany(vector <string> V) {  
2:         
3:    int N = V.size();  
4:    int M = V[0].size();  
5:    int res = 0;  
6:      
7:    for(int w=0; w < M; w++)  
8:    {  
9:      for(char ch = '0'; ch <= '9'; ch++)  
10:      {  
11:        bool isValid = true;  
12:        string ans = V[0];  
13:        ans[w] = ch;  
14:          
15:        for(int i=0; isValid && i < N; i++)  
16:        {  
17:          int diff = 0;  
18:            
19:          for(int j=0; j < M; j++)  
20:            if(V[i][j] != ans[j]) diff++;  
21:            
22:          if(diff != 1) isValid = false;  
23:        }  
24:        if(isValid) res++;  
25:      }  
26:    }  
27:      
28:    return res;  
29:  }  
30:    



Level Two - PasswordXGuessing


Source Code
1:    
2:  const int maxN = 45;  
3:  int dp[maxN][maxN];  
4:  int vert[maxN][maxN];  
5:  int hori[maxN][maxN];  
6:    
7:  int PasswordXGrid::minSum(vector <string> H, vector <string> V) {  
8:    
9:    int R = H.size();  
10:    int C = H[0].size()+1;  
11:      
12:    memset(dp, 0, sizeof(dp));  
13:    memset(hori, 0, sizeof(hori));  
14:    memset(vert, 0, sizeof(vert));  
15:      
16:    for(int i=0; i < R; i++)  
17:      for(int j=0; j < C-1; j++)  
18:        hori[i][j] = H[i][j] - '0';  
19:      
20:    for(int i=0; i < R-1; i++)  
21:      for(int j=0; j < C; j++)  
22:        vert[i][j] = V[i][j] - '0';  
23:    
24:    for(int i = R-1; i >= 0; i--)  
25:      for(int j= C-1; j >= 0; j--)  
26:        dp[i][j] = max(hori[i][j] + dp[i][j+1], vert[i][j] + dp[i+1][j]);  
27:    
28:    return dp[0][0];  
29:    
30:  }  


Level One - PasswordXPalindrome


Source Code
1:  int PasswordXPalindrome::minSwaps(string pwd) {  
2:      
3:    int N = pwd.size();  
4:    int res = 0;  
5:    bool soloChk = false;  
6:    for(int i = 0; i < N/2; i++)  
7:    {  
8:      if(pwd[i] == pwd[N-1-i]) continue;  
9:      bool found = false;  
10:      for(int j=i+1; !found && j < N-1-i; j++)  
11:        if(pwd[i] == pwd[j])  
12:        {  
13:          swap(pwd[j], pwd[N-1-i]);  
14:          res++;  
15:          found = true;  
16:        }  
17:      if(!found)  
18:      {  
19:        if(N%2 == 1 && !soloChk)  
20:        {  
21:          swap(pwd[i], pwd[N/2]);  
22:          res++;  
23:          soloChk = true;  
24:          i--;  
25:        }  
26:        else if(pwd[i] != pwd[N-1-i])  
27:          return -1;  
28:      }  
29:    }  
30:       return res;  
31:  }  


Sunday, April 8, 2012

TopCoder Open 2012 - Round 1B

All round 1 are held in 1:00AM  in my country.
So I have to either stay up late or sleep early and wake up to participate in the match.
In round 1A, I stayed up, and it was very tiring for me.
So this time, I decided to sleep early. How did it turn out?
When I woke up, the match was already over. OMG...
Nevertheless, I went to the practice room and tried to solve all problems.
Problems looked somewhat easier than the previous match (1A). What surprised me was that the cutoff for this match is a lot lower than 1A even though it seemed easier than the last match. I really should've participated in the match.
I solved 250 and 500 on my own, and got the correct answer.
I had trouble solving 1000, so I ended up looking at writer's solution, which was a lot simpler than I thought.

250 - FoxAndKgram
Approach
Let's turn this into a simpler problem.
Q1 : If we know the value of k (as in k-gram), is it possible to make it?
Note that we do not need to use all pencils, which means we can try the greedy approach.
Step 1) Find all pencils whose length is equal to k.
Step 2) Excluding pencils found in Step 1, find all pairs of pencils who sum is (k-1)
If number of pencils found in Step 1 and number of pairs of pencils found in Step 2 is bigger than or equal to k, it is possible.

Let N = number of pencils.
Then the above greedy approach takes O(2*N), or O(N), which is good enough considering the small constraint for N : 1 <= N <= 50

Now that we've found an efficient way to answer Q1, we can simply try all possible values of k.
Note that 1 <= k <= number of pencils. In other words, k cannot be higher than the number of pencils.
Proof : Yang takes one pencil, Yin takes two pencils, and each row has to be either Yang or Yin.
So each row needs at least one pencil, which means the maximum number of rows we can possibly create is the number of pencils.
So we basically try all possible k, and see if the current value for k is correct.
The overall running time is O(N) * O(N) = O(N^2)


Source Code
1:  bool isPossible(int);  
2:  vector<int> len;  
3:  int N;  
4:    
5:  int FoxAndKgram::maxK(vector <int> leng) {  
6:      
7:    len = leng;  
8:    N = len.size();  
9:    int res = 0;  
10:      
11:    for(int k=1; k <= N; k++)  
12:      if(isPossible(k))  
13:        res = k;  
14:      
15:    return res;  
16:  }  
17:    
18:  //return true if k is a valid k-gram value  
19:  bool isPossible(int k)  
20:  {  
21:    int res = 0;  
22:    vector<bool> used(N,false);  
23:      
24:    //find Yang  
25:    for(int i=0; i < N; i++)  
26:      if(len[i] == k)  
27:      {  
28:        used[i] = true;  
29:        res++;  
30:      }  
31:      
32:    //find Yin  
33:    for(int i=0; i < N; i++)  
34:      for(int j=i+1; j < N; j++)  
35:        if(!used[i] && !used[j] && (len[i] + len[j] + 1) == k)  
36:        {  
37:          used[i] = used[j] = true;  
38:          res++;  
39:        }  
40:      
41:    return res >= k;  
42:  }  
43:    



500 - FoxAndDoraemon
Approach
This can be solved using dynamic programming if we make a few key observations.

Observation 1 : It is optimal to start the longest work first.

Observation 2 : It is optimal to use the split hammer on all available foxes.
Explanation : This is an easy to miss observation. Note that the effect of the split hammer is instantaneous, which means it is possible to use the split hammer on multiple foxes at the same time (You can confirm this observation by looking at test case 1). We have problems when we have less foxes than we need, which means more foxes means better.

Let N = number of works.
Using Observation 1, let's sort all works in ascending order, and start by taking (N-1)th work.

Let's start doing dynamic programming.
Recurrence.
When processing (i)th job, we have two options
1) Split fox
2) Start the current job

Note that option 1) is unnecessary when you have more foxes than you need.
Als note that it is unwise to choose option 2) when you have only one fox left and there are more than moe jobs left.

State.
dp[i][j] = minimum number of time required to finish all jobs when there are [0...i) jobs left with j foxes.

Source Code
1:    
2:  const int maxN = 55;  
3:  int dp[maxN][maxN*2];  
4:  int N;  
5:  int splitC;  
6:  vector<int> workC;  
7:    
8:  int rec(int,int);  
9:  int FoxAndDoraemon::minTime(vector <int> workCost, int splitCost) {  
10:      
11:    sort(workCost.begin(), workCost.end());  
12:    N = workCost.size();  
13:    splitC = splitCost;  
14:    workC = workCost;  
15:       memset(dp, -1, sizeof(dp));  
16:      
17:    return rec(N-1, 1);  
18:  }  
19:    
20:  int rec(int jobs, int fox)  
21:  {  
22:    if(jobs == -1) return 0;  
23:      
24:    int& val = dp[jobs][fox];  
25:    if(val != -1) return val;  
26:    val = 0;  
27:      
28:    if( (jobs+1) <= fox) val = max(workC[jobs] , rec(jobs-1, fox-1));  
29:    else  
30:    {  
31:      //split fox  
32:      val = splitC + rec(jobs, fox + 1);  
33:        
34:      if( !(fox == 1 && jobs > 0) )  
35:        val = min(val, max(workC[jobs], rec(jobs-1, fox-1)));  
36:    }  
37:    return val;  
38:  }  
39:    

1000 - FoxAndPhotography
Approach
This problem can also solved using dynamic programming.
For each person in the first row, we need to determine where to put him.

Let N = number of members in heightsFront.

State
mask
= it is a bitmask representing which column has been taken care of.
= (i)th bit is 0 if (i)th column needs to be processed, and 1 if it is already processed.

dp[mask] 
= minimum number of swaps needed when the current state is mask.

Recurrence
At each state (mask, cur) where cur represents the current member of the first row we are looking at,
we need to decide where to put this guy.
Go through each member of the back row, and if the (i)th member of the back row is not processed and is taller than the current member of the first row, try putting the current guy in front of the (i)th person in the back row. Keep doing this until we assigned all members of the first row to their appropriate slots.
Now, you might be wondering below two questions.

Q1) It seems like the state consists of two variables : mask and cur. Then why are we not using "cur" in  dp, i.e. dp[mask][cur] ?
We start at mask = 0 (No front person is assigned to any position), and at each iteration, we assign one front person to a position, making one of N bits in mask 1.  Then (cur) is simply (N - number of unset bits in mask). So we really do not need to store "cur" as it is already encoded in mask.

Q2) How do we calculate how many swaps we need at each iteration?
At each iteration, the member in the first row who was originally at position (cur) is actually at the first unprocessed position of the back row. Let's take a look at test case 2.  I will color currently processed member blue, processed member red, and unprocessed member black.
Original position of the first row
140 141 142 143

Swapping process
 140 144 142 143
=> 141 140 142 143
=> 141 142 140 143
=> 141 142 143 140
=> 142 141 143 140
=> 142 143 141 140
=> 143 142 144 140
=> 143 142 144 140

So if we want to put the current member at (i)th position, the minimum number of swaps required is (number of unprocessed elements before i).

Source Code
1:    
2:  int dp[1<<16];  
3:  int N;  
4:  int INF = (15*16)/2 + 10;  
5:  vector<int> hF;  
6:  vector<int> hB;  
7:    
8:  int rec(int,int);  
9:    
10:  int FoxAndPhotography::getMinimumSwaps(vector <int> heightsFront, vector <int> heightsBack) {  
11:         
12:    hF = heightsFront;  
13:    hB = heightsBack;  
14:    N = hF.size();  
15:      
16:    memset(dp, -1, sizeof(dp));  
17:    int res = rec(0,0);  
18:    if(res >= INF) return -1;  
19:    return res;  
20:  }  
21:    
22:  int rec(int mask, int cur)  
23:  {  
24:    if(cur == N) return 0;  
25:      
26:    int& val = dp[mask];  
27:    if(val >= 0) return val;  
28:      
29:    val = INF;  
30:    int prev = 0;  
31:    for(int i=0; i < N; i++)  
32:    {  
33:      //If (i)th member in backrow is not taken care of,  
34:      //and if the person at position 'cur' at front row is  
35:      //shorter than (i)th person in backrow, try swappping.  
36:      if( (mask & (1<<i)) == 0)  
37:      {  
38:        if(hF[cur] < hB[i])  
39:          val = min(val, prev + rec( mask + (1<<i) , cur+1));  
40:        prev++;  
41:      }  
42:    }  
43:    return val;  
44:  }  

Wednesday, April 4, 2012

Croc Champ 2012 - Qualification Round

I am posting this before the system test ends.

I solved all 5 problems.
A,B,C, and D were easy enough to pass pretests in the first try.
However, it took me 4 wrong submissions to pass E.
Later I realized that I misunderstood the problem. Given query "a b b",
My thought : I have to find all possible sequence of a b b.
Answer : Find all element b who is the end element of the sequence a b b.

For example, given sequence <a><b><b><b></b></b></b></a>
Let's represent them a - b1 - b2 - b3
Given query a b b,
answer is  2  because b2 is the end element of (a b1 b2) and b3 is the end element of (a b1 b3 and a b2 b3)
I thought I had to output 3 because there are three possible sequence (a b1 b2, a b1 b3, a b2 b3).
After carefully reading the problem statement again, I realized the problem wanted the number of "ELEMENTS," not the number of "SEQUENCES".

Update :
Results are up. I am advancing to Round 1.
I passed A,B, and D, and failed C and E.
I was so sure about my solution to C, so I was curious why I failed system test.
I found out that I stupidly wrote
"const int maxS = 10010" even though the problem states that the maximum number of student is 10^5, or 100000.
So it should've been "maxS = 100010"
I fixed the mistake, I updated my solution to C in this blog accordingly.
I submitted my  fixed solution, but my submission is in queue for about 4 hours. Something must be wrong with codeforces server because a few others are also in queue.
My solution to C passed system test.

As for E, I received the verdict "time limit exceeded."
I am not sure what went wrong, but I will post about it as soon as I figure it out.
I solved E, and passed system test.

A. Phone Code
Approach
The constraints (2 <=n <= 3*10^4  , 1 <= length of phone number <= 20) are small enough to use simple brute force approach.

Step 1.
Let ans = the city phone code.
Let's make ans = the first phone code.

Step 2.
For each phone code, compare it to ans, and see if there is any mismatch. If there is, get rid of parts of ans that conflict with the current phone code.

Our answer is the size of ans.

Source Code
1:  int main()  
2:  {  
3:    ios_base::sync_with_stdio(false);  
4:    int N;  
5:    cin>>N;  
6:      
7:    string ans = "";  
8:    cin>>ans;  
9:      
10:    //It is guranteed that 2 <= N  
11:    for(int i=1; i < N; i++)  
12:    {  
13:      string cur;  
14:      cin>>cur;  
15:      int j = 0;  
16:      while(j < ans.size() && ans[j] == cur[j])  
17:        j++;  
18:        
19:      ans = ans.substr(0,j);  
20:    }  
21:      
22:    cout<<ans.size()<<endl;  
23:    
24:    return 0;  
25:  }  



B. Pseudorandom Sequence Period
Approach
The key to solving this problem is to notice that a cycle ends when the same value is produced twice as the result of mod operation.
So simulate the sequence until you see the same number twice. Let's call this twice-produced value C.
The answer is (the index of the second occurrence of C - the index of the first occurrence of C).
Note that M is at most 10^5, which means we will find our answer in at most 10^5 steps.

Source Code
1:  const int maxM = 100010;  
2:  int chk[maxM];  
3:    
4:  int main()  
5:  {  
6:    ios_base::sync_with_stdio(false);  
7:      
8:    int a,b,m,r0;  
9:      
10:    cin>>a>>b>>m>>r0;  
11:      
12:    memset(chk, -1, sizeof(chk));  
13:      
14:    int prev = (a*r0 + b) % m;  
15:    int idx = 1;  
16:    chk[prev] = idx;  
17:      
18:    while(true)  
19:    {  
20:      idx++;  
21:      int next = (a*prev + b) % m;  
22:      prev = next;  
23:      if(chk[next] != -1) break;  
24:      chk[next] = idx;  
25:    }  
26:    
27:    cout<<(idx - chk[prev])<<endl;  
28:    
29:    return 0;  
30:  }  


C. Bus
Approach
My first reaction when I saw this problem was "will it be okay to use plain-old simulation to solve this problem?" I did the following calculation, and found out the answer to my question is "Yes"
Let S = number of students, P = number of passengers the bus can transport.
At each "trip," bus the takes P students, so bus will make  (S/P) trips.
At each trip, I do follow operation
Step 1) Find out
F = the index of the first student to ride the bus
L = the index of the last student to ride the bus (it usually is F + P, but it can be lower if S < (F+P), in which case L   = S-1)

Step 2)
Sort all students in [F,L] by their drop-off location in ascending order.

Step 3)
Make necessary calculations according to the problem statement (refer to my source code).

Running time of each step is largely affected by Step 2, which takes O(P * logP)
So overall running time is O((S/P) * P * log(P))
The worst case will be S = 10^5, P = 1, a situation where there are maximum number of students but the bus can take only 1 person at a time.
The running time will be around 10^5.  This is small enough.

So all we have to do is simulate the problem according to the statement.
One thing to notice is that the time that although the max value of the time that a student gets dropped
is high, it barely fits into the max value of integer, 2,147,483,647. Let's think of the worst case where there are 10^5 students who all live at location 10^4 and there is a single bus. The last student will get to his home at  ( (10^5) * (10^4 * 2 + 1) + 10^5), which is around 2 * 10^9.
So it is okay to use int  to handle time. But I used long long just to be on the safe side.

Source Code
1:  struct Student  
2:  {  
3:    int time;  
4:    int loc;  
5:    int id;  
6:  };  
7:    
8:  const int maxS = 10010;   const int maxs = 100010;
9:  Student stu[maxS];  
10:  ll ans[maxS];  
11:    
12:  bool sortByLoc(Student a, Student b)  
13:  {  
14:    return a.loc < b.loc;  
15:  }  
16:    
17:  int main()  
18:  {  
19:    ios_base::sync_with_stdio(false);  
20:    
21:    int S,P;  
22:    cin>>S>>P;  
23:      
24:    for(int i=0; i < S; i++)  
25:    {  
26:      cin>>stu[i].time;  
27:      cin>>stu[i].loc;  
28:      stu[i].id = i;  
29:    }  
30:    
31:      
32:    ll curTime = 0LL;  
33:    
34:    int idx = 0;  
35:    while(idx < S)  
36:    {  
37:      int last = min(idx + P - 1, S - 1);  
38:      //The bus leaves when the last student arrives  
39:      curTime = max(curTime, ll(stu[last].time));  
40:    
41:      //The bus drops off student who lives closer to 0 first  
42:      sort(stu + idx, stu + (last + 1), sortByLoc);  
43:    
44:      int prevStop = 0;  
45:      while(idx <= last)  
46:      {  
47:        int k = 0;  
48:        int curStop = stu[idx].loc;  
49:        curTime += (curStop - prevStop);  
50:        while(idx<= last && stu[idx].loc == curStop)  
51:        {  
52:                      ans[stu[idx].id] = curTime;  
53:          idx++;  
54:          k++;  
55:        }  
56:        prevStop = curStop;  
57:        curTime += 1LL + (k/2);  
58:      }  
59:        
60:      //The bus goes back to position 0  
61:      curTime += stu[idx-1].loc;  
62:    }  
63:      
64:      
65:    cout<<ans[0];  
66:    for(int i=1; i < S; i++)  
67:      cout<<" "<<ans[i];  
68:    cout<<endl;  
69:      
70:    return 0;  
71:  }  


D. Calendar Reform
Approach
The concept of the problem is not hard to understand. The goal of this problem was to solve this as fast as possible (Notice the 4 seconds time limit).

The first thing I noticed was that we are testing consecutive values. This is a good place to start.
Notice that if X = multiple of a square number S, then all numbers (X + S*i) where ((X+ S*i) < (A + N)) are multiples of S.
Actually, if we make this observation, we are pretty much done because all we have to do is try all possible S.
Minimum S is, of course, 1.
Maximum S is a square number smaller than or equal to (A + N - 1).

In other words, 1 <= S <= (A+N-1)

Given N,
when S = 1 , we do N iterations.
when S = 4 , we do N / 4 iterations.
when S = 36, we do N / 36 iterations.
.....
when S = the biggest possible square number,  we do 1 iteration.

So running time is
N + N/4 + N/36 + ...... 1, which is around 2*N.

I ran my code against maximum inputs using Custom test, and results are following
(1, 10000000) => 480 ms
(2500000, 7500000) => 300 ms
(5000000, 5000000) => 230 ms
(7500000, 2500000) => 110 ms
(10000000, 1) => 10 ms

Looks like it would've been okay if the time limit was 2 seconds.
Either my solution is wrong, or the problem setter must have felt very generous when he set the time limit.

Note :
While reading my approach, have you kept thinking that my approach looks very familiar?
It should be because I got the idea from Sieve of Eratosthenes, a quick way to find whether each number in [1...N] is a prime or not.

Source Code
1:  const int maxN = 10000001;  
2:  ll arr[maxN];  
3:    
4:  int main()  
5:  {  
6:    ios_base::sync_with_stdio(false);  
7:      
8:    ll res = 0ll;  
9:      
10:    ll A,N;  
11:    cin>>A>>N;  
12:      
13:    for(int i=0; i < N; i++)  
14:    {  
15:      arr[i] = -1ll;  
16:    }  
17:      
18:    ll last = A+N-1ll;  
19:    ll lim = sqrt(last);  
20:    ll sq = 1ll;  
21:      
22:    while(sq <= lim)  
23:    {  
24:      ll cur = sq*sq;  
25:        
26:      ll idx = (cur * (A/cur) ) - A;  
27:            if(idx < 0) idx += cur;  
28:              
29:      while(idx < N)  
30:      {  
31:        arr[int(idx)] = cur;  
32:        idx += cur;  
33:      }  
34:      sq++;  
35:    }  
36:      
37:    for(int i=0; i < N; i++)  
38:      res += (A+i) / arr[i];  
39:      
40:    cout<<res<<endl;  
41:    return 0;  
42:  }  
43:    


E. BHTML+BCSS
Approach
We can use a tree structure to represent  "elements".
Each element will have a pointer pointing to its parent.

Every time we meet

<tag> : we make this node the child of the current node, and move to the child node.
</tag> : move to the parent of the current node.
<tag/> : make this node the child of the current node, and stay at the current node.

We can make "Dummy Root node" to have one giant tree, instead of separate disjoint trees, to avoid issue of trying to reach a parent of the actual root (there can be many root elements) when processing </tag>

To illustrate, let's represent the first sample input in tree structure.

<a><b><b></b></b></a><a><b></b><b><v/></b></a><b></b>

Once we represent the given input in a tree structure, query represents "parent - child" relationship.
So we basically need to traverse our graph to find subtree that matches the query's description.
To optimize my solution, I used an int array to save information on how many query relationships are already verified for each element.
More specifically, element i satisfies [query 0 ... query[solved[i]] ),  so child of element i needs to satisfy [query[solved[i]] ... last query].  Please look at my source for further clarification.


Note:
As dj3500 noted, using a tree structure is not the only correct approach to this problem. There is another approach that uses a stack of elements.
"... in E, it is actually not needed to create the tree data structure, it suffices to think that we are traversing the tree while parsing the input (because the input is given in the order in which we would traverse the tree anyway). We only need to maintain a current stack of tags (and, for every tag, the indexes i of the solved[i] that we will need to decrement when we close that tag).  - dj3500 "
Source Code

1:  struct Node  
2:  {  
3:    string data;  
4:    Node* parent;  
5:    int id;  
6:    Node(string d = "", Node* p = NULL, int i=-1)  
7:    {  
8:      data = d;  
9:      parent = p;  
10:      id = i;  
11:    }  
12:  };  
13:    
14:  const int maxDoc = 1e6 + 10;  
15:  const int maxNode = 3 * 1e5;  
16:  const int maxQuery = 210;  
17:  Node nodes[maxNode];  
18:  int solved[maxNode];  
19:  string query[maxQuery];  
20:  int main()  
21:  {  
22:    ios_base::sync_with_stdio(false);  
23:      
24:    string doc;  
25:    getline(cin, doc);  
26:    int idx = 1;  
27:    nodes[0] = Node("ROOT",NULL,0); //dummy root  
28:    Node* pt = &(nodes[0]);  
29:    int N = 1;//number of nodes  
30:      
31:    //process nodes  
32:    while(idx < doc.size())  
33:    {  
34:      if(doc[idx] == '/')  
35:      {  
36:        int j = idx+1;  
37:        while(doc[j] != '>')  
38:          j++;  
39:        idx = j + 2;  
40:        pt = (*pt).parent;  
41:      }  
42:      else  
43:      {  
44:        int j = idx;  
45:        while(doc[j] != '/' && doc[j] != '>')  
46:          j++;  
47:        nodes[N] = Node(doc.substr(idx, j - idx), pt, N);  
48:        if(doc[j] != '/') pt = &(nodes[N]);  
49:        else j++;  
50:            
51:        N++;  
52:        idx = j + 2;  
53:      }  
54:    }  
55:      
56:    int M;  
57:    cin>>M;  
58:    cin.ignore();  
59:    
60:    while(M--)  
61:    {  
62:      //process query  
63:      string line;  
64:      getline(cin, line);  
65:        
66:      int idx = 0;  
67:      int Q = 0; //number of queries  
68:    
69:      while(idx < line.size())  
70:      {  
71:        int j = idx;  
72:        while(j < line.size() && line[j] != ' ')  
73:          j++;  
74:        query[Q++] = line.substr(idx, j - idx);  
75:        idx = j+1;  
76:      }  
77:        
78:      int res = 0;  
79:      int solved[N];  
80:      solved[0] = 0;  
81:      //get answer  
82:      for(int i=1; i < N; i++)  
83:      {  
84:        int pos = solved[ (nodes[i].parent)->id ];  
85:        bool isMatch = (nodes[i].data == query[pos]);  
86:        if(isMatch)  
87:        {  
88:          if(pos == Q-1) res++;  
89:          else pos++;  
90:        }  
91:        solved[i] = pos;  
92:      }  
93:      cout<<res<<endl;  
94:    }  
95:    
96:    return 0;  
97:  }