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 |
676