// C++ program for building LCP array for given text
#include <bits/stdc++.h>
#include <vector>
#include <string>
#include <unordered_map>
#include <map>
#include <math.h>
#include <time.h>
using namespace std;
#define MAX 100000
#define mod 1000000007
long cum[MAX];
// Structure to store information of a suffix
struct suffix
{
int index; // To store original index
int rank[2]; // To store ranks and next rank pair
};
// A comparison function used by sort() to compare two suffixes
// Compares two pairs, returns 1 if first pair is smaller
int cmp(struct suffix a, struct suffix b)
{
return (a.rank[0] == b.rank[0])? (a.rank[1] < b.rank[1] ?1: 0):
(a.rank[0] < b.rank[0] ?1: 0);
}
// This is the main function that takes a string 'txt' of size n as an
// argument, builds and return the suffix array for the given string
vector<int>suffixArr;
void buildSuffixArray(string &txt, int n)
{
struct suffix suffixes[n];
for (int i = 0; i < n; i++)
{
suffixes[i].index = i;
suffixes[i].rank[0] = txt[i] - 'a';
suffixes[i].rank[1] = ((i+1) < n)? (txt[i + 1] - 'a'): -1;
}
sort(suffixes, suffixes+n, cmp);
int ind[n];
for (int k = 4; k < 2*n; k = k*2)
{
int rank = 0;
int prev_rank = suffixes[0].rank[0];
suffixes[0].rank[0] = rank;
ind[suffixes[0].index] = 0;
for (int i = 1; i < n; i++)
{
if (suffixes[i].rank[0] == prev_rank &&
suffixes[i].rank[1] == suffixes[i-1].rank[1])
{
prev_rank = suffixes[i].rank[0];
suffixes[i].rank[0] = rank;
}
else
{
prev_rank = suffixes[i].rank[0];
suffixes[i].rank[0] = ++rank;
}
ind[suffixes[i].index] = i;
}
for (int i = 0; i < n; i++)
{
int nextindex = suffixes[i].index + k/2;
suffixes[i].rank[1] = (nextindex < n)?
suffixes[ind[nextindex]].rank[0]: -1;
}
sort(suffixes, suffixes+n, cmp);
}
for (int i = 0; i < n; i++)
suffixArr.push_back(suffixes[i].index);
}
/* To construct and return LCP (longest common prefix) */
vector<int> lcp(MAX, 0);
vector<int> invSuff(MAX, 0);
void kasai(string &txt, vector<int> &suffixArr)
{
int n = suffixArr.size();
for (int i=0; i < n; i++)
invSuff[suffixArr[i]] = i;
int k = 0;
for (int i=0; i<n; i++)
{
if (invSuff[i] == n-1)
{
k = 0;
continue;
}
int j = suffixArr[invSuff[i]+1];
while (i+k<n && j+k<n && txt[i+k]==txt[j+k])
k++;
lcp[invSuff[i]] = k;
if (k>0)
k--;
}
}
// Utility function to print an array
void printArr(vector<int>&arr, int n)
{
for (int i = 0; i < n; i++)
cout << arr[i] << " ";
cout << endl;
}
// pow takes integer inputs and returns long long
// this function proves more accurate than math.pow, and quicker
long long ipow(int base_in, int exp)
{
long long result = 1;
long long base = (long long) base_in;
if (exp == 1)
return base;
while (exp)
{
if (exp & 1) {
result *= base;
result %= mod;
}
exp >>= 1;
base *= base;
base %= mod;
}
return result;
}
// store character frquency for each max length suffix
int dist_map[26];
string chars = "abcdefghijklmnopqrstuvwxyz";
// finds number of unique characters of substring by indexes
// checks for indexes in vector array pos >= begin and <= end
void distinct_substr_chars(string &s, int begin, int end)
{
for (int i = begin; i <= end; i++)
{
int c = s[i] - 'a';
dist_map[c]++;
}
}
void dist_map_clear()
{
//memset(dist_map,0,26);
for (int i = 0; i < 26; i++)
dist_map[i] = 0;
}
int dist_map_size()
{
int count = 0;
for (int i = 0; i < 26; i++)
if (dist_map[i] > 0)
count++;
return count;
}
// Driver program
int main()
{
int t;
cin >> t;
struct timespec start, finish;
double elapsed, total = 0;
while (t > 0)
{
string str;
cin >> str;
int n = str.length();
//Comment following 2 lines for hackerrank submission
clock_gettime(CLOCK_MONOTONIC, &start);
// build suffix array (vector)
buildSuffixArray(str, str.length());
// build lcp (longest common prefix) array (vector)
kasai(str, suffixArr);
// cum will hold number of unique substrings if that'a what you want (total = cum[n-1])
// Comment if not used
//cum[0] = n - suffixArr[0];
long long count = 0;
// loop through suffix array using lcp to get
// unique substring begin and end idexes
// then uses them to get substring length and
// count of distinct characters to perform function
int begin_suffix, suffix_len, suffix_end, begin, end;
int distinct_chars = 0, base, exp;
long long function_p;
begin = 1;
end = n - suffixArr[0];
for (int i = end; i >= begin; i--) {
begin_suffix = suffixArr[0];
suffix_len = i;
suffix_end = begin_suffix + suffix_len - 1;
if (i < end) {
// Decrement character frequency total count if necessary
// and update frquency map
int c = str[suffix_end+1] - 'a';
if (dist_map[c] == 1)
distinct_chars--;
dist_map[c]--;
}
else // i = max suffix length
{
// Get character frquency for suffix max length
dist_map_clear();
distinct_substr_chars(str, begin_suffix, suffix_end);
distinct_chars = dist_map_size();
}
base = suffix_len;
exp = distinct_chars;
function_p = ipow(base, exp);
count += function_p;
count %= mod;
}
// loop through suffix array using lcp to get
// unique substring begin and end idexes
// then uses them to get substring length and
// count of distinct characters to perform function
for(int i = 1;i < n;i++)
{
//Comment next line if not want total number of unique substrings
//cum[i] = cum[i-1] + (n - suffixArr[i] - lcp[i - 1]);
end = n - suffixArr[i];
begin = lcp[i-1] + 1;
begin_suffix = suffixArr[i];
for (int j = end, k = end - begin + 1 ; j >= begin; j--, k--) {
suffix_len = lcp[i-1] + k;
suffix_end = begin_suffix + suffix_len - 1;
if (j < end)
{
// Decrement character frequency total count if necessary
// and update frquency map
int c = str[suffix_end+1] - 'a';
if (dist_map[c] == 1)
distinct_chars--;
dist_map[c]--;
}
else // j = max suffix length
{
// Get character frquency for suffix max length
dist_map_clear();
distinct_substr_chars(str, begin_suffix, suffix_end);
distinct_chars = dist_map_size();
}
base = suffix_len;
exp = distinct_chars;
function_p = ipow(base,exp);
count += function_p;
count %= mod;
}
}
//Comment next 2 lines for hackerrank submission
//cout << endl << "Total unique substrings = " << cum[n-1] << endl << endl;
//cout << endl << "Result = ";
cout << count << endl;
suffixArr.clear();
lcp.clear();
invSuff.clear();
// Comment next 2 lines if not want total number of unique substrings
//for ( int j = 0; j < n; j++)
//cum[j] = 0;;
//Comment following 6 lines for hackerrank submission
clock_gettime(CLOCK_MONOTONIC, &finish);
elapsed = (finish.tv_sec - start.tv_sec);
elapsed += (finish.tv_nsec - start.tv_nsec) / 1000000000.0;
total += elapsed;
//cout << endl << "String \t\tExecution time = " << (int) elapsed /60 << " minutes " << fmod(elapsed,60)<< " seconds" << endl;
t--;
}
//Comment following line for hackerrank submission
cout << endl << "Total \t\tExecution time = " << (int) total /60 << " minutes " << fmod(total,60)<< " seconds" << endl;
return 0;
}