Find the numbers of strings that can be formed after processing Q queries
Given a number N(1<=N<=2000)., The task is to find the number strings of size N that can be obtained after using characters from 'a' to 'z' and by processing the given q(1<=q<=200000) queries.
For each query given two integers L, R (0<=L<=R<=N) such that substring [L, R] of the generated string of size N must be a palindrome. The task is to process all queries and generate a string of size N such that the substrings of this string defined by all queries are palindrome.
The answer can be very large. So, output answer modulo 1000000007.
Note: 1-based indexing is considered for the string.
Examples:
Input : N = 3 query 1: (1, 2) query 2: (2, 3) Output : 26 Explanation : Substring 1 to 2 should be palindrome and substring 2 to 3 should be palindrome. so, all three characters should be same. so, we can obtain 26 such strings. Input : N = 4 query 1: (1, 3) query 2: (2, 4) Output : 676 Explanation : substring 1 to 3 should be palindrome and substring 2 to 4 should be a palindrome. So, a first and third character should be the same and second and the fourth should be the same. So, we can obtain 26*26 such strings.
Approach : An efficient solution is to use union-find algorithm.
- Find the mid-point of each range (query) and if there are many queries having the same mid-point then only retain that query whose length is max, i.e (where r – l is max).
- This would have reduced the number of queries to 2*N at max since there is a 2*N number of mid-points in a string of length N.
- Now for each query do union of element l with r, (l + 1) with (r – 1), (l + 2) with (r – 2) and so on. We do this because the character which would be put on the index l would be the same as the one we put on index r. Extending this logic to all queries we need to maintain disjoint-set data structure. So basically all the elements of one component of disjoint-set should have the same letter on them.
- After processing all the queries, let the number of disjoint-set components be x, then the answer is 26^x
.
Below is the implementation of the above approach :
C++
// C++ program to implement above approach
#include <bits/stdc++.h>
using
namespace
std;
#define N 2005
#define mod (int)(1e9 + 7)
// To store the size of string and
// number of queries
int
n, q;
// To store parent and rank of ith place
int
par[N], Rank[N];
// To store maximum interval
map<
int
,
int
> m;
// Function for initialization
void
initialize()
{
for
(
int
i = 0; i <= n; i++) {
par[i] = i;
Rank[i] = 0;
}
}
// Function to find parent
int
find(
int
x)
{
if
(par[x] != x)
par[x] = find(par[x]);
return
par[x];
}
// Function to make union
void
Union(
int
x,
int
y)
{
int
xpar = find(x);
int
ypar = find(y);
if
(Rank[xpar] < Rank[ypar])
par[xpar] = ypar;
else
if
(Rank[xpar] > Rank[ypar])
par[ypar] = xpar;
else
{
par[ypar] = xpar;
Rank[xpar]++;
}
}
// Power function to calculate a raised to m1
// under modulo 10000007
int
power(
long
long
a,
long
long
m1)
{
if
(m1 == 0)
return
1;
else
if
(m1 == 1)
return
a;
else
if
(m1 == 2)
return
(1LL * a * a) % mod;
else
if
(m1 & 1)
return
(1LL * a * power(power(a, m1 / 2), 2)) % mod;
else
return
power(power(a, m1 / 2), 2) % mod;
}
// Function to take maxmium interval
void
query(
int
l,
int
r)
{
m[l + r] = max(m[l + r], r);
}
// Function to find different possible strings
int
possiblestrings()
{
initialize();
for
(
auto
i = m.begin(); i != m.end(); i++) {
int
x = i->first - i->second;
int
y = i->second;
// make union of all chracters which
// are meant to be same
while
(x < y) {
Union(x, y);
x++;
y--;
}
}
// find number of different sets formed
int
ans = 0;
for
(
int
i = 1; i <= n; i++)
if
(par[i] == i)
ans++;
// return the required answer
return
power(26, ans) % mod;
}
// Driver Code
int
main()
{
n = 4;
// queries
query(1, 3);
query(2, 4);
cout << possiblestrings();
return
0;
}
Java
// Java program to implement above approach
import
java.util.*;
class
GFG
{
static
final
int
N =
2005
;
static
final
int
mod =
1000000007
;
// To store the size of string and
// number of queries
static
int
n, q;
// To store parent and rank of ith place
static
int
[] par =
new
int
[N], Rank =
new
int
[N];
// To store maximum interval
static
HashMap<Integer,
Integer> m =
new
HashMap<>();
// Function for initialization
static
void
initialize()
{
for
(
int
i =
0
; i <= n; i++)
{
par[i] = i;
Rank[i] =
0
;
}
}
// Function to find parent
static
int
find(
int
x)
{
if
(par[x] != x)
par[x] = find(par[x]);
return
par[x];
}
// Function to make union
static
void
Union(
int
x,
int
y)
{
int
xpar = find(x);
int
ypar = find(y);
if
(Rank[xpar] < Rank[ypar])
par[xpar] = ypar;
else
if
(Rank[xpar] > Rank[ypar])
par[ypar] = xpar;
else
{
par[ypar] = xpar;
Rank[xpar]++;
}
}
// Power function to calculate a raised to m1
// under modulo 10000007
static
long
power(
long
a,
long
m1)
{
if
(m1 ==
0
)
return
1
;
else
if
(m1 ==
1
)
return
a;
else
if
(m1 ==
2
)
return
(1L * a * a) % mod;
else
if
(m1 %
2
==
1
)
return
(1L * a * power(power(a, m1 /
2
),
2
)) % mod;
else
return
power(power(a, m1 /
2
),
2
) % mod;
}
// Function to take maxmium interval
static
void
query(
int
l,
int
r)
{
if
(m.containsKey(l + r))
m.put(l + r, Math.max(m.get(l + r), r));
else
m.put(l + r, r);
}
// Function to find different possible strings
static
long
possiblestrings()
{
initialize();
for
(Integer i : m.keySet())
{
int
x = i - m.get(i);
int
y = m.get(i);
// make union of all chracters which
// are meant to be same
while
(x < y)
{
Union(x, y);
x++;
y--;
}
}
// find number of different sets formed
int
ans =
0
;
for
(
int
i =
1
; i <= n; i++)
if
(par[i] == i)
ans++;
// return the required answer
return
power(
26
, ans) % mod;
}
// Driver Code
public
static
void
main(String[] args)
{
n =
4
;
// queries
query(
1
,
3
);
query(
2
,
4
);
System.out.println(possiblestrings());
}
}
// This code is contributed by
// sanjeev2552
Python3
# Python3 program to implement above approach
N
=
2005
mod
=
10
*
*
9
+
7
# To store the size of string and
# number of queries
n, q
=
0
,
0
# To store parent and rank of ith place
par
=
[
0
for
i
in
range
(N)]
Rank
=
[
0
for
i
in
range
(N)]
# To store maximum interval
m
=
dict
()
# Function for initialization
def
initialize():
for
i
in
range
(n
+
1
):
Rank[i], par[i]
=
0
, i
# Function to find parent
def
find(x):
if
(par[x] !
=
x):
par[x]
=
find(par[x])
return
par[x]
# Function to make union
def
Union(x, y):
xpar
=
find(x)
ypar
=
find(y)
if
(Rank[xpar] < Rank[ypar]):
par[xpar]
=
ypar
elif
(Rank[xpar] > Rank[ypar]):
par[ypar]
=
xpar
else
:
par[ypar]
=
xpar
Rank[xpar]
+
=
1
# Power function to calculate a raised to m1
# under modulo 10000007
def
power(a, m1):
if
(m1
=
=
0
):
return
1
elif
(m1
=
=
1
):
return
a
elif
(m1
=
=
2
):
return
(a
*
a)
%
mod
elif
(m1 &
1
):
return
(a
*
power(power(a, m1
/
/
2
),
2
))
%
mod
else
:
return
power(power(a, m1
/
/
2
),
2
)
%
mod
# Function to take maxmium interval
def
query(l, r):
if
l
+
r
in
m.keys():
m[l
+
r]
=
max
(m[l
+
r], r)
else
:
m[l
+
r]
=
max
(
0
, r)
# Function to find different possible strings
def
possiblestrings():
initialize()
for
i
in
m:
x
=
i
-
m[i]
y
=
m[i]
# make union of all chracters which
# are meant to be same
while
(x < y):
Union(x, y)
x
+
=
1
y
-
=
1
# find number of different sets formed
ans
=
0
for
i
in
range
(
1
, n
+
1
):
if
(par[i]
=
=
i):
ans
+
=
1
# return the required answer
return
power(
26
, ans)
%
mod
# Driver Code
n
=
4
# queries
query(
1
,
3
)
query(
2
,
4
)
print
(possiblestrings())
# This code is contributed by Mohit Kumar
C#
// C# program to implement above approach
using
System;
using
System.Collections.Generic;
class
GFG{
const
int
N = 2005;
const
int
mod = 1000000007;
// To store the size of string and
// number of queries
static
int
n;
//static int q;
// To store parent and rank of ith place
static
int
[]par =
new
int
[N];
static
int
[]Rank =
new
int
[N];
// To store maximum interval
static
Dictionary<
int
,
int
> m =
new
Dictionary<
int
,
int
>();
// Function for initialization
static
void
initialize()
{
for
(
int
i = 0; i <= n; i++)
{
par[i] = i;
Rank[i] = 0;
}
}
// Function to find parent
static
int
find(
int
x)
{
if
(par[x] != x)
par[x] = find(par[x]);
return
par[x];
}
// Function to make union
static
void
Union(
int
x,
int
y)
{
int
xpar = find(x);
int
ypar = find(y);
if
(Rank[xpar] < Rank[ypar])
par[xpar] = ypar;
else
if
(Rank[xpar] > Rank[ypar])
par[ypar] = xpar;
else
{
par[ypar] = xpar;
Rank[xpar]++;
}
}
// Power function to calculate a raised to m1
// under modulo 10000007
static
long
power(
long
a,
long
m1)
{
if
(m1 == 0)
return
1;
else
if
(m1 == 1)
return
a;
else
if
(m1 == 2)
return
(1L * a * a) % mod;
else
if
(m1 % 2 == 1)
return
(1L * a * power(
power(a, m1 / 2), 2)) % mod;
else
return
power(power(a, m1 / 2), 2) % mod;
}
// Function to take maxmium interval
static
void
query(
int
l,
int
r)
{
if
(m.ContainsKey(l + r))
m[l + r] = Math.Max(m[l + r], r);
else
m[l + r] = r;
}
// Function to find different possible strings
static
long
possiblestrings()
{
initialize();
foreach
(KeyValuePair<
int
,
int
> i
in
m)
{
int
x = i.Key - m[i.Key];
int
y = m[i.Key];
// Make union of all chracters
// which are meant to be same
while
(x < y)
{
Union(x, y);
x++;
y--;
}
}
// Find number of different sets formed
int
ans = 0;
for
(
int
i = 1; i <= n; i++)
if
(par[i] == i)
ans++;
// Return the required answer
return
power(26, ans) % mod;
}
// Driver Code
public
static
void
Main(
string
[] args)
{
n = 4;
// Queries
query(1, 3);
query(2, 4);
Console.Write(possiblestrings());
}
}
// This code is contributed by rutvik_56
Output:676