# Pseudo-Isomorphic Substrings

### Problem Statement :

```wo strings A and B, consisting of small English alphabet letters are called pseudo-isomorphic if

Their lengths are equal
For every pair (i,j), where 1 <= i < j <= |A|, B[i] = B[j], iff A[i] = A[j]
For every pair (i,j), where 1 <= i < j <= |A|, B[i] != B[j] iff A[i] != A[j]

Naturally, we use 1-indexation in these definitions and |A| denotes the length of the string A.

You are given a string S, consisting of no more than 105 lowercase alphabetical characters. For every prefix of S denoted by S', you are expected to find the size of the largest possible set of strings , such that all elements of the set are substrings of S' and no two strings inside the set are pseudo-isomorphic to each other.

if S = abcde
then, 1st prefix of S is 'a'
then, 2nd prefix of S is 'ab'
then, 3rd prefix of S is 'abc'
then, 4th prefix of S is 'abcd' and so on..

Input Format

The first and only line of input will consist of a single string S. The length of S will not exceed 10^5.

Constraints

1  <=   |  S  |   <=  10^5
S contains only lower-case english alphabets ('a' - 'z').

Output Format

Output N lines. On the ith line, output the size of the largest possible set for the first i alphabetical characters of S such that no two strings in the set are pseudo-isomorphic to each other.```

### Solution :

```                            ```Solution in C :

In   C++  :

#include <algorithm>
#include <iostream>
#include <iomanip>
#include <complex>
#include <cstring>
#include <cstdlib>
#include <string>
#include <vector>
#include <cstdio>
#include <cmath>
#include <map>
#include <set>
using namespace std;

const int MaxLen = 200001;
const int MaxLog = 21;
int lg[MaxLen], tmp[200001];
int S[MaxLen];

struct SuffixArray
{
int rank [MaxLen], SA[MaxLen], h[MaxLen], D[MaxLen];
int n, dep , count_rank [MaxLen], f[MaxLog][MaxLen];
void Build ()
{
for(int len = 1; len < n; len <<= 1)
{
fill ( count_rank , count_rank + 1 + n, 0);
for (int i=1;i <=n;++ i)
++ count_rank [ rank [SA[i]+ len ]];
for (int i=1;i <=n;++ i)
count_rank [i]+= count_rank [i -1];
for (int i=n;i >0;--i)
D[ count_rank [ rank [SA[i]+ len ]]--] = SA[i];
fill ( count_rank , count_rank + 1 + n, 0);
for (int i=1;i <=n;++ i)
++ count_rank [ rank [SA[i ]]];
for (int i=1;i <=n;++ i)
count_rank [i]+= count_rank [i -1];
for (int i=n;i >0;--i)
SA[ count_rank [ rank [D[i]]] --] = D[i];
copy (rank , rank + 1 + n, D);
rank [SA [1]]=1;
for (int i=2;i <=n;++ i)
if(D[SA[i]] != D[SA[i -1]] ||
D[SA[i]+ len] != D[SA[i -1] + len ])
rank [SA[i ]]= rank [SA[i -1]]+1;
else
rank [SA[i ]]= rank [SA[i -1]];
if( rank [SA[n]] == n) break ;
}
}
int strsuf (int *p, int *q)
{
int ret =0;
for (; *p == *q; ++p, ++q, ++ ret );
return ret;
}
void CalcHeight ()
{
for (int i=1;i <=n;++ i)
{
if( rank [i] == 1)
h[i] = 0;
else
if(i == 1 || h[i -1] <= 1)
h[i]= strsuf (S+i, S+SA[ rank [i] -1]);
else
h[i]= strsuf (S+i+h[i -1] -1 ,
S+SA[ rank [i] -1]+h[i -1] -1)+ h[i -1] -1;
f [0][ rank [i]]=h[i];
}
dep =1;
for (int len =1; len *2 <=n;len <<=1 , dep ++)
for(int i=1; i+len *2 -1 <=n;++ i)
f[dep ][i]= min(f[dep -1][ i],f[dep -1][ i+len ]);
}
void init ( int _n) // String Stored in (S +1)
{
lg[1] = 0;
for(int i = 2; i <= _n; i++)
lg[i] = lg[i/2] + 1;
n = _n;
memset (tmp ,0, sizeof ( tmp ));
for (int i=1;i <=n;++ i)
++ tmp[S[i ]];
for (int i=1;i <=10000;++ i)tmp [i]+= tmp [i -1];
for (int i=n;i >0;--i)
SA[ tmp[S[i]] --]=i;
rank [SA [1]]=1;
for (int i=2;i <=n;++ i)
if(S[SA[i]] != S[SA[i -1]])
rank [SA[i]] = rank [SA[i -1]]+1;
else
rank [SA[i]] = rank [SA[i -1]];
Build ();
CalcHeight ();
}
inline int lcp( int a, int b)
{ // lcp of S[a] and S[b]
if(a == b) return n - a + 1;
a = rank [a], b = rank [b];
if(a > b) swap (a, b);
int d = lg[b - a];
if ((1 << d) == (b - a)) return f[d][a +1];
else return min(f[d][a+1] , f[d][b -(1<<d )+1]);
}
}mySA;

int n;
string s;
int prevSame[100001];
int prevSame_chr[26];

int sa[100011], rank_in_sa[100011];
int height[100011];
int minv_left[100011], minv_right[100011];
long long ans[100011];

bool cmpSuffix(int a, int b)
{
for(int i = 0; i <= n; )
{
if(a + i > n) return true;
if(b + i > n) return false;
int v1 = prevSame[a+i], v2 = prevSame[b+i];
if(v1 > i) v1 = 0;
if(v2 > i) v2 = 0;
if(v1 != v2)
return v1 > v2;
if(n <= 100)
i ++;
else
i += max(1, mySA.lcp(a+i, b+i));

}
return 0;
}

int MAIN()
{
cin >> s;
n = s.length();
s = " " + s;
for(int i = 1; i <= n/2; i++)
swap(s[i], s[n+1-i]);
memset(prevSame_chr, 0xe, sizeof(prevSame_chr));
for(int i = 1; i <= n; i++)
{
prevSame[i] = min(i, prevSame_chr[s[i]-'a']);
prevSame[i] = i - prevSame[i];
prevSame_chr[s[i]-'a'] = i;
S[i] = prevSame[i];
}
mySA.init(n);
for(int i = 1; i <= n; i++)
sa[i] = i;
sort(sa + 1, sa + 1 + n, cmpSuffix);
for(int i = 1; i <= n; i++)
rank_in_sa[sa[i]] = i;
int curH = 0;
for(int i = 1; i <= n; i++)
{
curH = max(0, curH - 26);
if(i == n)
height[rank_in_sa[i]] = 0;
else
{
int t = sa[rank_in_sa[i]-1];
while(true)
{
if(i + curH > n || t + curH > n)
break;
int v1 = prevSame[i+curH], v2 = prevSame[t+curH];

if(v1 > curH) v1 = 0;
if(v2 > curH) v2 = 0;
if(v1 != v2) break;
curH ++;
}
height[rank_in_sa[i]] = curH;
}
}

sa[0] = 0;
sa[n+1] = n+1;
height[n+1] = 0;
for(int i = 0; i <= n; i++)
{
int a = sa[i], b = sa[i+1], v = height[i+1];
minv_left[b] = v;
minv_right[a] = v;
}

for(int i = 1; i <= n; i++)
{
ans[i] = (n+1-i) - max(minv_left[i], minv_right[i]);

int nv = min(minv_left[i], minv_right[i]);
minv_right[a] = nv;
minv_left[b] = nv;
}

for(int i = n-1; i >= 1; i--)
ans[i] += ans[i+1];

for(int i = n; i >= 1; i--)
cout << ans[i] << endl;

return 0;
}

int main()
{
#ifdef LOCAL_TEST
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
ios :: sync_with_stdio(false);
cout << fixed << setprecision(16);
return MAIN();
}

In   Java  :

import java.io.IOException;
import java.io.PrintWriter;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.NavigableSet;
import java.util.Random;
import java.util.StringTokenizer;
import java.util.TreeSet;

public class Solution implements Runnable {
static Random RND = new Random(7777L);
static int MAX_LENGTH = 100000;
static int ALPHA_SIZE = 26;
static int HASH_BASE = BigInteger.probablePrime(17, RND).intValue();
static int[] HASH_BASE_POWS = new int[MAX_LENGTH * 2];

static {
HASH_BASE_POWS[0] = 1;

for (int i = 1; i < HASH_BASE_POWS.length; i++) {
HASH_BASE_POWS[i] = HASH_BASE_POWS[i - 1] * HASH_BASE;
}
}

char[] s;
int length;
int[][] charMaps;
int[][] charPerms;
int[][] distributedHashes;
int[] hashPrefixes;
Map<Long, Integer> lcpCache = new HashMap<Long, Integer>();

void solve() throws IOException {
length = s.length;
charMaps = getCharMaps(s);
charPerms = getCharPermutations(charMaps);
distributedHashes = getDistributedHashes(s);
hashPrefixes = precalcHashPrefixes(charPerms, distributedHashes);
Integer[] suffixArray = getSuffixArray();
final int[] suffixIndex = new int[length];

for (int i = 0; i < length; i++) {
suffixIndex[suffixArray[i]] = i;
}

NavigableSet<Integer> viewedSuffixes = new TreeSet<Integer>(
new Comparator<Integer>() {
@Override
public int compare(Integer pos1, Integer pos2) {
return (suffixIndex[pos1] - suffixIndex[pos2]);
}
});

long[] counts = new long[length + 1];

for (int pos = length - 1; pos >= 0; pos--) {
long intersectionSize = 0L;

{
Integer neigbourPos = viewedSuffixes.lower(pos);

if (neigbourPos != null) {
\intersectionSize = Math.max(intersectionSize,
lcp(pos, neigbourPos));
}
}

{
Integer neigbourPos = viewedSuffixes.higher(pos);

if (neigbourPos != null) {
intersectionSize = Math.max(intersectionSize,
lcp(pos, neigbourPos));
}
}

counts[pos] = counts[pos + 1] + length - pos - intersectionSize;
}

for (int i = 0; i < length; i++) {
out.println(counts[length - 1 - i]);
}
}

Integer[] getSuffixArray() {
Integer[] suffixArray = new Integer[length];

for (int i = 0; i < length; i++) {
suffixArray[i] = i;
}

Arrays.sort(suffixArray, new Comparator<Integer>() {
@Override
public int compare(Integer pos1, Integer pos2) {
if (pos1.equals(pos2)) {
return 0;
}

int lcp = lcp(pos1, pos2);

if (lcp == length - pos1) {
return -1;
}

if (lcp == length - pos2) {
return +1;
}

return charMaps[pos1][s[pos1 + lcp] - 'a']
- charMaps[pos2][s[pos2 + lcp] - 'a'];
}
});

return suffixArray;
}

int lcp(int pos1, int pos2) {
if (pos1 > pos2) {
return lcp(pos2, pos1);
}

int leftBound = 0;
int rightBound = length - pos2;
int lcp = naiveLcp(pos1, pos2, Math.min(120, rightBound));

if (lcp == -1) {
leftBound = Math.min(15, rightBound);

while (leftBound <= rightBound) {
int middlePoint = (leftBound + rightBound) >> 1;

if (equals(pos1, pos2, middlePoint)) {
lcp = Math.max(lcp, middlePoint);
leftBound = middlePoint + 1;
} else {
rightBound = middlePoint - 1;
}
}
}

return lcp;
}

int naiveLcp(int pos1, int pos2, int len) {
int[] map1 = charMaps[pos1];
int[] map2 = charMaps[pos2];

for (int i = 0; i < len; i++) {
if (map1[s[pos1 + i] - 'a'] != map2[s[pos2 + i] - 'a']) {
return i;
}
}

return -1;
}

boolean equals(int pos1, int pos2, int length) {
if (pos1 > pos2) {
return equals(pos2, pos1, length);
}

int hash1 = hash(pos1, length);
int hash2 = hash(pos2, length);
int hashAlingmentPower = HASH_BASE_POWS[pos2 - pos1];

return hashAlingmentPower * hash1 == hash2;
}

int hash(int pos, int length) {
int[] perm = charPerms[pos];
int[] hashes = distributedHashes[pos + length];
int hash = -hashPrefixes[pos];

for (int rank = 0; rank < perm.length; rank++) {
hash += hashes[perm[rank]] * rank;
}

return hash;
}

static int[][] getCharMaps(char[] s) {
int length = s.length;
int[][] maps = new int[length][ALPHA_SIZE];

for (int offset = 0; offset < length; offset++) {
int[] map = maps[offset];
Arrays.fill(map, -1);
int mapped = 0;
map[s[offset] - 'a'] = mapped++;

for (int pos = offset; pos < length;) {
int nextPos = length;
int nextChar = -1;

for (int ch = 0; ch < ALPHA_SIZE; ch++) {
if (map[ch] == -1) {
nextChar = ch;
}
}
}

if (nextChar == -1) {
break;
}

map[nextChar] = mapped++;
pos = nextPos;
}
}

return maps;
}

int length = s.length;

for (int[] row : linksToNext) {
Arrays.fill(row, length);
}

for (int i = length - 2; i >= 0; i--) {
ALPHA_SIZE);
linksToNext[i][s[i + 1] - 'a'] = i + 1;
}

}

static int[][] getDistributedHashes(char[] s) {
int length = s.length;
int[][] distributedHashes = new int[length + 1][ALPHA_SIZE];

for (int i = 0; i < length; i++) {
System.arraycopy(distributedHashes[i], 0, distributedHashes[i + 1],
0, ALPHA_SIZE);
distributedHashes[i + 1][s[i] - 'a'] += HASH_BASE_POWS[i];
}

return distributedHashes;
}

static int[][] getCharPermutations(int[][] charMaps) {
int lenght = charMaps.length;
int[][] charPerms = new int[lenght][];

for (int pos = 0; pos < lenght; pos++) {
charPerms[pos] = getCharPermutation(charMaps[pos]);
}

return charPerms;
}

static int[] getCharPermutation(int[] map) {
int[] permutation = new int[ALPHA_SIZE];
int last = 0;

for (int ch = 0; ch < ALPHA_SIZE; ch++) {
if (map[ch] != -1) {
permutation[map[ch]] = ch;
last = Math.max(last, map[ch]);
}
}

return Arrays.copyOf(permutation, last + 1);
}

static int[] precalcHashPrefixes(int[][] charPerms,
int[][] distributedHashes) {
int length = charPerms.length;
int[] hashPreffixes = new int[length];

for (int pos = 0; pos < length; pos++) {
int[] hashes = distributedHashes[pos];
int[] perm = charPerms[pos];

for (int rank = 0; rank < charPerms[pos].length; rank++) {
hashPreffixes[pos] += hashes[perm[rank]] * rank;
}
}

return hashPreffixes;
}

static Solution INSTANCE = new Solution();
static boolean WRITE_LOG = true;
static long STACK_SIZE = -1;

public static void main(String[] args) throws IOException {
try {
if (STACK_SIZE < 0L) {
INSTANCE.run();
} else {
new Thread(null, INSTANCE, "Solver", 1L << 24).start();
}
} catch (Throwable e) {
e.printStackTrace();
System.exit(999);
}
}

@Override
public void run() {
try {
out = new PrintWriter(System.out);
solve();
out.close();
in.close();
} catch (Throwable e) {
e.printStackTrace();
System.exit(999);
}
}

PrintWriter out;
StringTokenizer st = new StringTokenizer("");

String nextToken() throws IOException {
while (!st.hasMoreTokens()) {
}

return st.nextToken();
}

int nextInt() throws IOException {
return Integer.parseInt(nextToken());
}

long nextLong() throws IOException {
return Long.parseLong(nextToken());
}

double nextDouble() throws IOException {
return Double.parseDouble(nextToken());
}

int[] nextIntArray(int size) throws IOException {
int[] ret = new int[size];

for (int i = 0; i < size; i++) {
ret[i] = nextInt();
}

return ret;
}

long[] nextLongArray(int size) throws IOException {
long[] ret = new long[size];

for (int i = 0; i < size; i++) {
ret[i] = nextLong();
}

return ret;
}

double[] nextDoubleArray(int size) throws IOException {
double[] ret = new double[size];

for (int i = 0; i < size; i++) {
ret[i] = nextDouble();
}

return ret;
}

String nextLine() throws IOException {
st = new StringTokenizer("");

}

boolean isEof() throws IOException {
while (!st.hasMoreTokens()) {

if (s == null) {
return true;
}

st = new StringTokenizer(s);
}

return false;
}

void printRepeat(String s, int count) {
for (int i = 0; i < count; i++) {
out.print(s);
}
}

void printArray(int[] array) {
if (array == null || array.length == 0) {
return;
}

for (int i = 0; i < array.length; i++) {
if (i > 0) {
out.print(' ');
}

out.print(array[i]);
}

out.println();
}

void printArray(long[] array) {
if (array == null || array.length == 0) {
return;
}

for (int i = 0; i < array.length; i++) {
if (i > 0) {
out.print(' ');
}

out.print(array[i]);
}

out.println();
}

void printArray(double[] array) {
if (array == null || array.length == 0) {
return;
}

for (int i = 0; i < array.length; i++) {
if (i > 0) {
out.print(' ');
}

out.print(array[i]);
}

out.println();
}

void printArray(double[] array, String spec) {
if (array == null || array.length == 0) {
return;
}

for (int i = 0; i < array.length; i++) {
if (i > 0) {
out.print(' ');
}

out.printf(Locale.US, spec, array[i]);
}

out.println();
}

void printArray(Object[] array) {
if (array == null || array.length == 0) {
return;
}

boolean blank = false;

for (Object x : array) {
if (blank) {
out.print(' ');
} else {
blank = true;
}

out.print(x);
}

out.println();
}

@SuppressWarnings("rawtypes")
void printCollection(Collection collection) {
if (collection == null || collection.isEmpty()) {
return;
}

boolean blank = false;

for (Object x : collection) {
if (blank) {
out.print(' ');
} else {
blank = true;
}

out.print(x);
}

out.println();
}

static void swap(int[] a, int i, int j) {
int tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}

static void swap(long[] a, int i, int j) {
long tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}

static void swap(double[] a, int i, int j) {
double tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}

static void shuffle(int[] a, int from, int to) {
for (int i = from; i < to; i++) {
swap(a, i, RND.nextInt(a.length));
}
}

static void shuffle(long[] a, int from, int to) {
for (int i = from; i < to; i++) {
swap(a, i, RND.nextInt(a.length));
}
}

static void shuffle(double[] a, int from, int to) {
for (int i = from; i < to; i++) {
swap(a, i, RND.nextInt(a.length));
}
}

static void shuffle(int[] a) {
if (a == null) {
return;
}

shuffle(a, 0, a.length);
}

static void shuffle(long[] a) {
if (a == null) {
return;
}

shuffle(a, 0, a.length);
}

static void shuffle(double[] a) {
if (a == null) {
return;
}

shuffle(a, 0, a.length);
}

static long[] getPartialSums(int[] a) {
long[] sums = new long[a.length + 1];

for (int i = 0; i < a.length; i++) {
sums[i + 1] = sums[i] + a[i];
}

return sums;
}

static long[] getPartialSums(long[] a) {
long[] sums = new long[a.length + 1];

for (int i = 0; i < a.length; i++) {
sums[i + 1] = sums[i] + a[i];
}

return sums;
}

static int[] getOrderedSet(int[] a) {
int[] set = Arrays.copyOf(a, a.length);

if (a.length == 0) {
return set;
}

shuffle(set);
Arrays.sort(set);
int k = 1;
int prev = set[0];

for (int i = 1; i < a.length; i++) {
if (prev != set[i]) {
set[k++] = prev = set[i];
}
}

return Arrays.copyOf(set, k);
}

static long[] getOrderedSet(long[] a) {
long[] set = Arrays.copyOf(a, a.length);

if (a.length == 0) {
return set;
}

shuffle(set);
Arrays.sort(set);
int k = 1;
long prev = set[0];

for (int i = 1; i < a.length; i++) {
if (prev != set[i]) {
set[k++] = prev = set[i];
}
}

return Arrays.copyOf(set, k);
}

static int gcd(int x, int y) {
x = Math.abs(x);
y = Math.abs(y);

while (x > 0 && y > 0) {
if (x > y) {
x %= y;
} else {
y %= x;
}
}

return x + y;
}

static long gcd(long x, long y) {
x = Math.abs(x);
y = Math.abs(y);

while (x > 0 && y > 0) {
if (x > y) {
x %= y;
} else {
y %= x;
}
}

return x + y;
}
}

In   Python3   :

s = input()

prevs = dict()
a = []
for i in range(len(s)):
if s[i] in prevs:
a.append(i - prevs[s[i]])
else:
a.append(i + 1)
prevs[s[i]] = i

class Node:
def __init__(self, **d):
self.__dict__ = d

class Edge:
def __init__(self, **d):
self.__dict__ = d

root = Node(edges = dict(), depth = 0, slink = None)
edge0 = Edge(a = root, b = root, u = 0, l = 0)
cur = (edge0, 0, 0)
leaves = 0
ans = 0

def conv(c, depth):
return -1 if c > depth else c

def simplify(cur):
edge, u, l = cur
while l > edge.l:
c = conv(a[u + edge.l], edge.a.depth + edge.l)
edge, u, l = edge.b.edges[c], u + edge.l, l - edge.l
return edge, u, l

def toStr(a, depth):
l = []
for i in range(len(a)):
l.append(conv(a[i], depth + i))
return map(str, l)

def printTree(edge, tabs = ''):
print(tabs + ':'.join(toStr(a[edge.u:edge.u+edge.l], edge.a.depth)),
for e in edge.b.edges.values():
printTree(e, tabs + '  ')

edge, u, l = cur
if edge.a == root:
assert(edge != edge0)
return simplify((edge0, u + 1, l - 1))
else:
return simplify((e1, u - l1, l + l1))

#print(':'.join(map(str, a)))

for i in range(len(s)):
while True:
edge, u, l = cur
c = conv(a[i], edge.a.depth + l)
if l == edge.l:
if c in edge.b.edges:
break
leaves += 1
leaf = Node(depth = -1, slink = None, edges = dict())
edge.b.edges[c] = Edge(a = edge.b, b = leaf, u = i, l = len(s) - i)
else:
c1 = conv(a[edge.u + l], edge.a.depth + l)
if c == c1:
break
leaves += 1
leaf = Node(depth = -1, slink = None, edges = dict())
branch = Node(edges = dict(), depth = edge.a.depth + l, slink = slink(cur))
branch.edges[c] = Edge(a = branch, b = leaf, u = i, l = len(s) - i)
branch.edges[c1] = Edge(a = branch, b = edge.b, u = edge.u + l, l = edge.l - l)
edge.b = branch
edge.l = l
if edge == edge0 and l == 0:
cur = None
break
if edge.a == root:
assert(edge != edge0)
cur = simplify((edge0, u + 1, l - 1))
else:
cur = simplify((e1, u - l1, l + l1))
if cur == None:
cur = edge0, i + 1, 0
else:
edge, u, l = cur
assert(u + l == i)
cur = simplify((edge, u, l + 1))
ans += leaves
print(ans)
#printTree(edge0)```
```

## Array and simple queries

Given two numbers N and M. N indicates the number of elements in the array A[](1-indexed) and M indicates number of queries. You need to perform two types of queries on the array A[] . You are given queries. Queries can be of two types, type 1 and type 2. Type 1 queries are represented as 1 i j : Modify the given array by removing elements from i to j and adding them to the front. Ty

The median M of numbers is defined as the middle number after sorting them in order if M is odd. Or it is the average of the middle two numbers if M is even. You start with an empty number list. Then, you can add numbers to the list, or remove existing numbers from it. After each add or remove operation, output the median. Input: The first line is an integer, N , that indicates the number o

## Maximum Element

You have an empty sequence, and you will be given N queries. Each query is one of these three types: 1 x -Push the element x into the stack. 2 -Delete the element present at the top of the stack. 3 -Print the maximum element in the stack. Input Format The first line of input contains an integer, N . The next N lines each contain an above mentioned query. (It is guaranteed that each

## Balanced Brackets

A bracket is considered to be any one of the following characters: (, ), {, }, [, or ]. Two brackets are considered to be a matched pair if the an opening bracket (i.e., (, [, or {) occurs to the left of a closing bracket (i.e., ), ], or }) of the exact same type. There are three types of matched pairs of brackets: [], {}, and (). A matching pair of brackets is not balanced if the set of bra

## Equal Stacks

ou have three stacks of cylinders where each cylinder has the same diameter, but they may vary in height. You can change the height of a stack by removing and discarding its topmost cylinder any number of times. Find the maximum possible height of the stacks such that all of the stacks are exactly the same height. This means you must remove zero or more cylinders from the top of zero or more of

## Game of Two Stacks

Alexa has two stacks of non-negative integers, stack A = [a0, a1, . . . , an-1 ] and stack B = [b0, b1, . . . , b m-1] where index 0 denotes the top of the stack. Alexa challenges Nick to play the following game: In each move, Nick can remove one integer from the top of either stack A or stack B. Nick keeps a running sum of the integers he removes from the two stacks. Nick is disqualified f