Super palindromes#470

Super palindromes (Editorial)

Let be the input string. A substring s_i ... s_j is a palindrome if at least one of the following conditions is satisfied:

Let's define the function IsPal, that returns if the substring s_i ... s_j is a palindrome, and otherwise.

To speed up the algorithm, the values of IsPal(i, j) are stored in the cells of a two-dimensional array pal[i][j].

A string is called a superpalindrome if it can be represented as a concatenation of one or more palindromes. For example, the following strings are superpalindromes:

Let

dp[i][j] = \begin{cases} 1, & \text{if the substring } s_i \ldots s_j\ (i < j) \text{ is a superpalindrome}, \\ 0, & \text{ otherwise}. \end{cases}

Here it is assumed that i < j, that is, the length of the substring is at least two.

Let us note the base cases:

dp[i][j] = 0~при~i ≥ j

If the substring s_i ... s_j is a palindrome and its length is at least two, then it is automatically a superpalindrome (since it consists of a single palindrome). Therefore, for all pairs of indices where 0 \le i < j < n, if the substring s_i ... s_j is a palindrome, we can immediately set dp[i][j] = 1.

Now consider the general case. Let the substring s_i ... s_j not be a palindrome as a whole. It can still be a superpalindrome if it can be split into two parts, each of which is a superpalindrome.

To do this, iterate over all possible split positions such that i < k < j - 1.

The restriction k < j - 1 ensures that both substrings

s_i ... s_k~и~s_{k+1} ... s_j

have length at least two, and therefore can potentially be superpalindromes.

If, for some , the following conditions are satisfied:

then the substring s_i ... s_j can be represented as a concatenation of two superpalindromes. Therefore, it is itself a superpalindrome, and we set dp[i][j] = 1.

If this condition is not satisfied for any valid , then dp[i][j] remains .

Finally, count the number of pairs for which i < j and dp[i][j] = 1. This count is exactly the number of substrings of the string that are superpalindromes.

Example

For the given example — the string "" — there are substrings that are superpalindromes:

For the string "", there are substrings that are superpalindromes:

Algorithm implementation

Declare the arrays.

#define MAX 1010
char s[MAX];
int dp[MAX][MAX];
int pal[MAX][MAX];

The function IsPal checks whether the substring s_i \ldots s_j is a palindrome. The substring s_i \ldots s_j is a palindrome if s_i = s_j and the substring s_{i + 1} \ldots s_{j - 1} is also a palindrome. The values of the function IsPal are stored in the cells of the two-dimensional array pal[i][j].

int IsPal(int i, int j)
{
  if (i >= j) return pal[i][j] = 1;
  if (pal[i][j] != -1) return pal[i][j];
  return pal[i][j] = (s[i] == s[j]) && IsPal(i + 1,j - 1);
}

The main part of the program. Read the input string and compute its length .

cin >> s; n = s.size();

Initialize the arrays and .

memset(dp,0,sizeof(dp));
memset(pal,-1,sizeof(pal));

Iterate over all substrings s_i \ldots s_{i + len} of the string in increasing order of their length . This is important because the value of dp[i][j] depends on the values for shorter substrings.

for (len = 1; len < n; len++)
for (i = 0; i + len < n; i++)
{

The right boundary of the substring s_i \ldots s_{i + len} is j = i + len.

  j = i + len;

If the substring s_i \ldots s_j is a palindrome, then it is automatically also a superpalindrome.

  if (IsPal(i,j))
  {
    dp[i][j] = 1;
    continue;
  }

If the substring s_i \ldots s_j is not a palindrome, we try to represent it as a concatenation of two superpalindromes.

If s_i \ldots s_k and s_{k+1} \ldots s_j are superpalindromes, then s_i \ldots s_j is a superpalindrome as well.

  for (k = i + 1; k < j - 1; k++)
    if (dp[i][k] && dp[k + 1][j])
    {
      dp[i][j] = 1;
      break;
    }
}

Count the number of superpalindromes. It is equal to the number of index pairs (i, j) for which dp[i][j] = 1.

res = 0;
for (i = 0; i < n; i++)
for (j = i + 1; j < n; j++)
  res += dp[i][j];

Print the answer.

printf("%d\n",res);

Algorithm implementation – recursion

Declare the input string and arrays.

#define MAX 1010
string s;
int dp[MAX][MAX], pal[MAX][MAX];

The function IsPal checks whether the substring s_i \ldots s_j is a palindrome. The substring s_i \ldots s_j is a palindrome if s_i = s_j and the substring s_{i + 1} \ldots s_{j - 1} is also a palindrome. The values of the function IsPal are stored in the cells of the two-dimensional array pal[i][j].

int IsPal(int i, int j)
{
  if (i >= j) return pal[i][j] = 1;
  if (pal[i][j] != -1) return pal[i][j];
  return pal[i][j] = (s[i] == s[j]) && IsPal(i+1,j-1);
}

The function f returns if the substring s_i \ldots s_j is a superpalindrome.

int f(int i, int j)
{

A superpalindrome must contain more than one character.

  if (i == j) return dp[i][j] = 0;

If the value of f is already computed, return this value.

  if (dp[i][j] != -1) return dp[i][j];

If the substring s_i \ldots s_j~(i < j) is a palindrome, then it is also a superpalindrome.

  if (IsPal(i,j)) return dp[i][j] = 1;

If the substring s_i \ldots s_k~(i < k) is a palindrome and the substring s_{k+1} \ldots s_j~(k + 1 < j) is a superpalindrome, then the substring s_i \ldots s_j is a superpalindrome.

  for (int k = i + 1; k < j - 1; k++)
    if (IsPal(i,k) && f(k + 1,j)) return dp[i][j] = 1;

If none of the conditions described above is satisfied, then the substring s_i \ldots s_j is not a superpalindrome.

  return dp[i][j] = 0;
}

The main part of the program. Read the input string and compute its length .

cin >> s; n = s.size();

Initialize the arrays and .

memset(dp,-1,sizeof(dp));
memset(pal,-1,sizeof(pal));

In the variable count the number of superpalindromes.

res = 0;
for (i = 0; i < n; i++)
for (j = i + 1; j < n; j++)
  res += f(i,j);

Print the answer.

cout << res << endl;

Java implementation

import java.util.*;

public class Main 
{
  static String s;
  static int dp[][], pal[][];

  static int IsPal(int i, int j)
  {
    if (i >= j) return pal[i][j] = 1;
    if (pal[i][j] != -1) return pal[i][j];
    if (s.charAt(i) == s.charAt(j) && IsPal(i+1,j-1) == 1) pal[i][j] = 1;
    else pal[i][j] = 0;
    return pal[i][j];
  }
 
  static int f(int i, int j)
  {
    if (i == j) return dp[i][j] = 0;
    if (dp[i][j] != -1) return dp[i][j];
    if (IsPal(i,j) == 1) return dp[i][j] = 1;

    for(int k = i + 1; k < j - 1; k++)
      if(IsPal(i,k) == 1 && f(k + 1,j) == 1) return dp[i][j] = 1;

    return dp[i][j] = 0;
  }
	
  public static void main(String[] args) 
  {
    Scanner con = new Scanner(System.in);
    s = con.nextLine();
    int n = s.length();
    dp = new int[n][n];
    pal = new int[n][n];
    for(int i = 0; i < n; i++)
    for(int j = 0; j < n; j++)
    {
      dp[i][j] = -1;
      pal[i][j] = -1;
    }

    int res = 0;
    for(int i = 0; i < n; i++)
    for(int j = i+1; j < n; j++)
      res += f(i,j);
    
    System.out.println(res);
    con.close();
  }
}