HackerRank Shashank and the Palindromic Strings
In this post, we will solve HackerRank Shashank and the Palindromic Strings Problem Solution.
Shashank loves strings, but he loves palindromic strings the most. He has a list of n strings.
A = [ao, a1,…, an-1]. where each string, a,, consists of lowercase English alphabetic letters. Shashank wants to count the number of ways of choosing non-empty
subsequences 80, 81, 82, …, 8-1 such that the following conditions are satisfied:
1.80 is a subsequence of string ap. 81 is a subsequence of string a1, 82 is a subsequence of string a2….. and 8-1 is a subsequence of string an-1.
2.80 +81 +82 + … + 8-1 is a palindromic string, where + denotes the string concatenation operator.
You are given q queries where each query consists of some list. A. For each query, find and print the number of ways Shashank can choose n non-empty subsequences satisfying the criteria above, modulo 109 +7, on a new line.
Note: Two subsequences consisting of the same characters are considered to be different if their characters came from different indices in the original string.
Input Format
The first line contains a single integer. q. denoting the number of queries. The subsequent lines describe each query in the following format:
- The first line contains an integer, n. denoting the size of the list.
- Each line i of the n subsequent lines contains a non-empty string describing a,.
Sample Input 0
3
3
aa
b
aa
3
a
b
c
2
abc
abc
Sample Output 0
5
0
9
Explanation 0
The first two queries are explained below:
- We can choose the following five subsequences:
1.50 “a”. 81=”b”, s₂ = “a”, where so is the first character of ap and 82 is the first character of a2.
2.80= “a”, 81 = “b”, 82=”a”, where so is the second character of a and 82 is the second character of a2.
3.50″a”. 81 “b”, 82 = second character of a2. = “a”, where so is the first character of ap and 82 is the - 50 “a”, 81 = “b”, 82 the first character of a2. = “a”, where 80 is the second character of a, and 82 is
- So “aa”, s = “b”, 82 = “aa”
Thus, we print the result of 5 mod (109 +7)= 5 on a new line. - There is no way to choose non-empty subsequences such that their concatenation results in a palindrome, as each string contains unique characters. Thus, we print 0 on a new line.
Shashank and the Palindromic Strings C Solution
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#define md 1000000007
char cv[1001], fv[1000], lv[1000], gv[1000];
unsigned int mv[1000 * 1000 * 4];
int m;
void readInput() {
int i, j, k, l, n;
char *s;
for (i = 0; i < 1000; ++i)
{
fv[i] = 0;
lv[i] = 0;
}
s = cv;
k = 0;
scanf("%d", &n);
for (i = 0; i < n; ++i)
{
scanf("%s", s);
l = strlen(s);
fv[k] = 1;
lv[k + l - 1] = 1;
for (j = 0; j < l; ++j)
{
gv[k + j] = i;
}
k += l;
s += l;
}
m = strlen(cv);
}
int ix(int i, int j, int oi, int oj) {
return (i * m * 4) + (j * 4) + (oi * 2) + oj;
}
unsigned int f(int i, int j, int oi, int oj) {
if (i == j)
{
return (oi || oj) ? 2 : 1;
}
if (j < i)
{
return 1;
}
if (gv[i] == gv[j])
{
oi = oi || oj;
oj = oi;
}
return mv[ix(i, j, oi, oj)];
}
void run() {
int l, i, j, p;
int il, jf, oi, oj, oi1, oj1, b1, b2;
unsigned int c;
readInput();
for (l = 2; l <= m; ++l)
{
for (i = 0; i <= m - l; ++i)
{
j = i + l - 1;
for (p = 0; p < 4; ++p)
{
if (p == 0 || p == 3 || gv[i] < gv[j])
{
il = lv[i];
jf = fv[j];
oi = p & 1;
oj = p >> 1;
c = 0;
b1 = oi || !il;
b2 = oj || !jf;
oi1 = !il && oi;
oj1 = !jf && oj;
if (b1)
{
c += f(i + 1, j, oi1, oj);
}
if (b2)
{
c += f(i, j - 1, oi, oj1);
}
if (b1 && b2 && (l > 2 || oi || oj))
{
c += md - f(i + 1, j - 1, oi1, oj1);
}
if (cv[i] == cv[j])
{
c += f(i + 1, j - 1, !il, !jf);
}
mv[ix(i, j, oi, oj)] = c % md;
}
}
}
}
printf("%u\n", mv[ix(0, m - 1, 0, 0)]);
}
int main() {
int q, i;
scanf("%d", &q);
for(i = 0; i < q; ++i) {
run();
}
return 0;
}
Shashank and the Palindromic Strings C++ Solution
#include <algorithm>
#include <cstring>
#include <iostream>
#include <type_traits>
#include <utility>
using namespace std;
#define FOR(i, a, b) for (remove_cv<remove_reference<decltype(b)>::type>::type i = (a); i < (b); i++)
#define REP(i, n) FOR(i, 0, n)
#define ROF(i, a, b) for (remove_cv<remove_reference<decltype(b)>::type>::type i = (b); --i >= (a); )
const long L = 1000, MOD = 1000000007;
char a[L+1], b[L+1];
long s[L][L][2][2], p[L][L][2][2], d[L];
int main()
{
cin.sync_with_stdio(0);
cin.tie(0);
long cases, n, m;
for (cin >> cases; cases--; ) {
cin >> n;
fill_n(b, L+1, 0);
m = 0;
REP(i, n) {
cin >> a+m;
b[m] = 1;
m += strlen(a+m);
}
REP(i, m)
b[i+1] += b[i];
memset(s, 0, sizeof s);
memset(p, 0, sizeof s);
REP(i, m)
REP(x, 2)
REP(y, 2)
s[i][i][x][y] = 1;
ROF(i, 0, m) {
FOR(j, i+1, m)
REP(x, 2)
REP(y, 2) {
long l = b[i+1]-b[i],
// do not take i
c = ! x && l ? 0 : s[i+1][j][l ? b[i+1] == b[j] ? y : 0 : x][y];
// single i
if (b[j]-b[i] <= y)
c++;
// pair (i, k+1)
c += p[i+1][j][x][y];
s[i][j][x][y] = c%MOD;
}
if (i)
REP(x, 2)
REP(y, 2) {
long ps = 0, t = y, jj = i-1, c;
FOR(j, i, m) {
c = 0;
if (a[i-1] == a[j]) {
long x1 = 1-(b[i]-b[i-1]), y1 = 1-(b[j]-b[j-1]);
if (b[i] == b[j-1])
x1 = y1 = 1;
c += s[i][j-1][x1][y1];
if (b[j]-b[i-1] <= 1)
c++;
}
ps += d[j] = c%MOD;
if (b[j]-b[j-1] && --t < 0)
for(;;) {
if (i <= jj)
ps -= d[jj];
jj++;
if (b[jj]-b[jj-1]) {
t++;
break;
}
}
p[i][j][x][y] = ps%MOD;
}
}
}
cout << s[0][m-1][0][0] << '\n';
}
}
Shashank and the Palindromic Strings C Sharp Solution
using System;
using System.Collections.Generic;
using System.IO;
class Solution {
static bool DEBUG = false;
const int MODULO = 1000000007;
string S;
int Len;
int[] Start; // Start index of this string
int[] End; // End index of this string
int[] sIndex; // Index of this letter's string
int[] Prev; // Last letter of previous string
int[] Next; // First letter of next string
long[,] DP; // [i,j] = CPS of the substring from i to j (from the whole constructed string)
static void Main(String[] args) {
int T = Convert.ToInt32(Console.ReadLine());
for (int t = 0; t < T; t++) {
int N = Convert.ToInt32(Console.ReadLine());
int N2 = N + 2;
string[] A = new string[N];
string[] A2 = new string[N2]; // Add extra "a" onto beginning and end to avoid edge cases
A2[0] = "a";
for (int n = 0; n < N; n++) {
A[n] = Console.ReadLine();
A2[n+1] = A[n];
}
A2[N2-1] = "a";
//Solution soln = new Solution(N, A);
//long result = soln.Solve(N, A, MODULO);
Solution soln = new Solution(N2, A2);
long result = soln.Solve(N2, A2, MODULO);
Console.WriteLine(result);
}
}
public Solution(int N, string[] A) {
S = "";
Start = new int[N];
End = new int[N];
int length = 0;
for (int n = 0; n < N; n++) {
S += A[n];
Start[n] = length;
length += A[n].Length;
End[n] = length-1;
}
Len = length;
DP = new long[Len, Len];
sIndex = new int[Len];
Prev = new int[Len];
Next = new int[Len];
for (int n = 0; n < N; n++) {
for (int i = 0; i < A[n].Length; i++) {
sIndex[Start[n]+i] = n;
if (n > 0)
Prev[Start[n]+i] = End[n-1];
if (n < N-1)
Next[Start[n]+i] = Start[n+1];
}
}
}
long Solve(int N, string[] A, int mod) {
if (DEBUG) {
Console.WriteLine("A = " + ArrayToString(A));
Console.WriteLine("S = {0}, Len = {1}", S, Len);
Console.WriteLine("Start = " + ArrayToString(Start));
Console.WriteLine("End = " + ArrayToString(End));
Console.WriteLine("sIndex = " + ArrayToString(sIndex));
Console.WriteLine("Prev = " + ArrayToString(Prev));
Console.WriteLine("Next = " + ArrayToString(Next));
}
return CPS(A, mod);
}
long CPS(string[] A, int mod) {
for (int i = 0; i < Len; i++)
DP[i, i] = 1;
for (int len = 2; len <= Len; len++) {
for (int i = 0; i <= Len-len; i++) {
// Num palindromes, starting at i (or later, but in same string) and ending at j (or before, but in same string)
int j = i + len - 1;
int state = 0;
if (sIndex[i] == sIndex[i+1]) { // If i+1 letter is part of i string then add
DP[i, j] = Mod(DP[i, j] + DP[i+1, j], mod);
state += 1;
}
if (sIndex[j] == sIndex[j-1]) { // If j-1 letter is part of j string then add
DP[i, j] = Mod(DP[i, j] + DP[i, j-1], mod);
state += 2;
}
if (state == 3) // If both states above occurred then subtract the duplicate amount
DP [i, j] = Mod(DP[i, j] - DP[i+1, j-1],mod);
if (S[i] == S[j]) { // If the letters are the same add the extra palindromes
DP[i, j] = Mod(DP[i, j] + DP[i+1, j-1], mod);
state = 0;
if (Next[i] != i+1) { // If we're not at the end of i string
DP[i, j] = Mod(DP[i, j] + DP[Next[i], j-1], mod);
state += 1;
}
if (Prev[j] != j-1) { // If we're not at the start of j string
DP[i, j] = Mod(DP[i, j] + DP[i+1, Prev[j]], mod);
state += 2;
}
if (state == 3) // If both states above occurred then add the next strings as well
DP[i, j] = Mod(DP[i, j] + DP[Next[i], Prev[j]], mod);
if (sIndex[i]+1 == sIndex[j] || sIndex[i] == sIndex[j]) // If i and j are in the middle or middle two strings
DP[i, j] = Mod(DP[i, j] + 1, mod);
}
}
}
long result = DP[0, Len-1];
return result;
}
// Returns the total number of palindromic subsequences for a single string s
long CountPS(int start, string s, int mod) {
int N = s.Length;
//long[,] DP = new long[N, N]; // [i, j] = CPS of substring starting at i and ending at j
for (int i = start; i < start+N; i++) // Single letters are all palindromes
DP[i, i] = 1;
for (int len = 2; len <= N; len++) { // Check all substrings of length len
for (int i = start; i <= start+N-len; i++) {
int j = i + len - 1;
if (S[i] == S[j])
DP[i, j] = (DP[i, j-1] + DP[i+1, j] + 1) % mod;
else
DP[i, j] = (DP[i, j-1] + DP[i+1, j] - DP[i+1, j-1]) % mod;
}
}
if (DEBUG) {
Console.WriteLine("DP:");
PrintDP(S, DP);
}
return DP[start, start+N-1];
}
// Returns the total number of palindromic subsequences between 2 strings
long CountPS(int start, string s1, string s2, int mod) {
int N1 = s1.Length;
int N2 = s2.Length;
string s = s1 + s2;
int N = N1 + N2;
if (DEBUG) Console.WriteLine("s={0}", s);
long[,] DP1 = new long[N, N]; // [i, j] = CPS of substring starting at i and ending at j
for (int i = 0; i < N; i++) // Single letters are all palindromes
DP1[i, i] = 1;
for (int len = 2; len <= N; len++) { // Check all substrings of length len (must be 2 and above)
for (int i = 0; i <= N-len; i++) {
int j = i + len - 1;
if (s[i] == s[j]) {
DP1[i, j] = (DP1[i, j-1] + DP1[i+1, j] - DP1[i+1, j-1] + DP1[i+1, j-1] + 1) % mod;
if (i < N1 && j >= N1) // If i is part of s1 and j is part of s2, then valid substring
DP[start+i, start+j] = (DP[start+i, start+j-1]
+ DP[start+i+1, start+j]
- DP[start+i+1, start+j-1]
+ DP1[i+1, j-1] + 1) % mod;
} else {
DP1[i, j] = (DP1[i, j-1] + DP1[i+1, j] - DP1[i+1, j-1]) % mod;
if (i < N1 && j >= N1) // If i is part of s1 and j is part of s2, then valid substring
DP[start+i, start+j] = (DP[start+i, start+j-1]
+ DP[start+i+1, start+j]
- DP[start+i+1, start+j-1]) % mod;
}
}
}
if (DEBUG) {
Console.WriteLine("DP1:");
PrintDP(s, DP1);
Console.WriteLine("DP:");
PrintDP(S, DP);
}
return DP[start, start+N-1];
}
// Returns the total number of palindromic subsequences between 3 strings
long CountPS(int start, string s1, string m, string s2, int mod) {
int N1 = s1.Length;
int Nm = m.Length;
int N2 = s2.Length;
string s = s1 + m + s2;
int N = N1 + Nm + N2;
if (DEBUG) Console.WriteLine("s={0}", s);
long[,] DP1 = new long[N, N]; // Using single string
for (int i = 0; i < N; i++) {
if (i >= N1 && i < N1+Nm) // Copy from DP
DP1[i, i] = DP[i, i];
else // Else single letters are palindrome
DP1[i, i] = 1;
}
long[,] DP2 = new long[N, N]; // Using 2 strings
for (int len = 2; len <= N; len++) { // Check all substrings of length len (must be 2 and above)
for (int i = 0; i <= N-len; i++) {
int j = i + len - 1;
if (s[i] == s[j]) {
if (i >= N1 && i < N1+Nm && j >= N1 && j < N1+Nm) { // Inside middle string, copy from DP
DP1[i, j] = DP[start+i, start+j];
} else if (i < N1 && j >= N1+Nm) { // Inside valid range (i within s1, j within s2)
DP1[i, j] = (DP1[i, j-1] + DP1[i+1, j] + 1) % mod;
DP2[i, j] = (DP2[i, j-1] + DP2[i+1, j] - DP2[i+1, j-1] + DP1[i+1, j-1] + 1) % mod;
if (i == N1-1 && j == N1+Nm)
DP[start+i, start+j] = 0;
else
DP[start+i, start+j] = (DP[start+i, start+j-1]
+ DP[start+i+1, start+j]
- DP[start+i+1, start+j-1]
+ DP2[i+1, j-1] + 1) % mod;
} else { // Inside range using only 2 strings (middle and one of s1 or s2)
DP1[i, j] = (DP1[i, j-1] + DP1[i+1, j] + 1) % mod;
DP2[i, j] = (DP2[i, j-1] + DP2[i+1, j] - DP2[i+1, j-1] + DP1[i+1, j-1] + 1) % mod;
}
} else {
if (i >= N1 && i < N1+Nm && j >= N1 && j < N1+Nm) { // Inside middle string, copy from DP
DP1[i, j] = DP[start+i, start+j];
} else if (i < N1 && j >= N1+Nm) { // Inside valid range (i within s1, j within s2)
DP1[i, j] = (DP1[i, j-1] + DP1[i+1, j] - DP1[i+1, j-1]) % mod;
DP2[i, j] = (DP2[i, j-1] + DP2[i+1, j] - DP2[i+1, j-1]) % mod;
if (i == N1-1 && j == N1+Nm)
DP[start+i, start+j] = 0;
else
DP[start+i, start+j] = (DP[start+i, start+j-1]
+ DP[start+i+1, start+j]
- DP[start+i+1, start+j-1]) % mod;
} else { // Inside range using only 2 strings (middle and one of s1 or s2)
DP1[i, j] = (DP1[i, j-1] + DP1[i+1, j] - DP1[i+1, j-1]) % mod;
DP2[i, j] = (DP2[i, j-1] + DP2[i+1, j] - DP2[i+1, j-1]) % mod;
}
}
}
}
if (DEBUG) {
Console.WriteLine("DP1:");
PrintDP(s, DP1);
Console.WriteLine("DP2:");
PrintDP(s, DP2);
Console.WriteLine("DP:");
PrintDP(S, DP);
}
return DP[start, start+N-1];
}
long Mod(long x, int mod) {
return (x % mod + mod) % mod;
}
string ArrayToString<T>(IEnumerable<T> collection) {
return "[" + string.Join(",", collection) + "]";
}
void PrintMatrix(int[,] M) {
int I = M.GetLength(0);
int J = M.GetLength(1);
for (int i = 0; i < I; i++) {
for (int j = 0; j < J-1; j++)
Console.Write("{0},", M[i, j]);
if (J > 0)
Console.Write("{0}", M[i, J-1]);
Console.WriteLine();
}
}
void PrintDP(string s, long[,] M) {
int I = M.GetLength(0);
int J = M.GetLength(1);
Console.Write(" ");
for (int i = 0; i < I; i++)
Console.Write(" {0}", s[i]);
Console.WriteLine();
for (int i = 0; i < I; i++) {
Console.Write("{0}|", s[i]);
for (int j = 0; j < J-1; j++)
Console.Write("{0},", M[i, j]);
if (J > 0)
Console.Write("{0}", M[i, J-1]);
Console.WriteLine();
}
}
}
Shashank and the Palindromic Strings Java Solution
import java.io.*;
import java.util.*;
public class Solution {
static final int A = 26 * 4;
static final int MASKS = A + 4;
static final int MOD = 1_000_000_007;
static int solve(char[][] parts, int n) {
int m = parts.length;
int[] s = new int[n];
boolean[] edge = new boolean[n + 1];
edge[0] = true;
for (int i = 0, j = 0; i < m; i++) {
for (int k = 0; k < parts[i].length; k++) {
s[j++] = (parts[i][k] - 'a') << 2;
}
edge[j] = true;
}
int[][] a = new int[n + 1][MASKS];
int[][] b = new int[n + 1][MASKS];
a[0][A + 3] = 1;
for (int len = n; len > 0; len--) {
Arrays.fill(b[0], 0);
for (int i = 0; i <= n - len; i++) {
int j = i + len;
int leftNext = edge[i + 1] ? 2 : 0;
int rightNext = edge[j - 1] ? 1 : 0;
int[] ai = a[i];
int[] bi = b[i];
int[] bi1 = b[i + 1];
Arrays.fill(bi1, 0);
int si = s[i];
int sj = s[j - 1];
for (int mask = 0; mask < MASKS; mask++) {
int value = ai[mask];
if (value == 0) {
continue;
}
int letter = mask & ~3;
int left = mask & 2;
int right = mask & 1;
int index;
if (letter == A) {
index = si | leftNext | right;
bi1[index] = (bi1[index] + value) % MOD;
if ((leftNext & left) == 0) {
index = A | leftNext | left | right;
bi1[index] = (bi1[index] + value) % MOD;
}
} else {
if (sj == letter) {
index = A | left | rightNext;
bi[index] = (bi[index] + value) % MOD;
}
if ((rightNext & right) == 0) {
index = letter | left | rightNext | right;
bi[index] = (bi[index] + value) % MOD;
}
}
}
}
int[][] temp = a;
a = b;
b = temp;
}
int ans = 0;
for (int i = 0; i <= n; i++) {
for (int mask = 0; mask < MASKS; mask++) {
if (!edge[i] && (mask & 3) == 3) {
continue;
}
ans = (ans + a[i][mask]) % MOD;
}
}
return ans;
}
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new FileWriter(System.getenv("OUTPUT_PATH")));
StringTokenizer st = new StringTokenizer(br.readLine());
int q = Integer.parseInt(st.nextToken());
for (int i = 0; i < q; i++) {
st = new StringTokenizer(br.readLine());
int m = Integer.parseInt(st.nextToken());
char[][] parts = new char[m][];
int n = 0;
for (int j = 0; j < m; j++) {
parts[j] = br.readLine().toCharArray();
n += parts[j].length;
}
long result = solve(parts, n);
bw.write(String.valueOf(result));
bw.newLine();
}
br.close();
bw.close();
}
}