(codeforces - 149d) colouring brackets (interval DP)

Posted by polybiosis on Fri, 18 Feb 2022 16:01:13 +0100

Title Link: https://codeforces.com/problemset/problem/149/D

Meaning:

Given a string s, it is a legal sequence of parentheses. We intend to dye this bracket sequence with the following requirements:

  • There are three conditions for each character: no dyeing, red dyeing and blue dyeing
  • Each pair of matching parentheses has and only one character is colored
  • All two adjacent characters cannot be dyed in the same color

Find the number of bracket sequence coloring schemes that meet the requirements, the answer may be large, and output the result of modulo 109 + 7.

This problem is solved by interval DP. First, dp[i][j] represents the starting position of the interval. Let's take a look at the conditions. There are requirements for the color of two adjacent characters and matching characters, so we must add two dimensions to represent the color of points at both ends of the interval, Generally speaking, dp[i][j][k][l] represents the number of cases in which the left end is tinged with No. K color and the right end is tinged with No. l color, where 0 represents colorless, 1 represents red and 2 represents blue. Let's look at the state transition equation below:

First of all, we must update the interval i to j in two cases. One is that i and j match, and the other is that i and j do not match. Therefore, we must first deal with the string and find out the position of the character matching each character. Of course, this can be easily solved by stack.

If I and j are matched, the interval [i+1,j-1] is related to the interval [i,j]. Because i+1 and j-1 are also matched, we only care about this interval. The requirement is that the i+1 character cannot be the same color as the I character (but both can be colorless), and the j-1 character cannot be the same color as the j character, so this is easier to handle, The state transition equation is as follows:

for(int k=0;k<=2;k++)
            for(int l=0;l<=2;l++)
            {
                if(l!=1) dp[i][j][0][1]=(dp[i][j][0][1]+dp[i+1][j-1][k][l])%mod;
                if(l!=2) dp[i][j][0][2]=(dp[i][j][0][2]+dp[i+1][j-1][k][l])%mod;
                if(k!=1) dp[i][j][1][0]=(dp[i][j][1][0]+dp[i+1][j-1][k][l])%mod;
                if(k!=2) dp[i][j][2][0]=(dp[i][j][2][0]+dp[i+1][j-1][k][l])%mod;
            }

Looking at this transfer equation, we find that if the interval length is 2 and the two characters match, we need to deal with it separately, because DP [i] [J] (I > J) is meaningless. Obviously, in this case, we can directly set all four legal cases to 1

Let's take a look at the case where I and j do not match. Then we need to divide the interval into two sections, one is [i,match[i]] and the other is [match[i]+1,j]. We only need to multiply the legal conditions of the two sections and take the sum. It should also be noted that the color of the end points between the regions cannot be the same. The state transition equation is as follows:

else//match[i]!=j
        {
            int t=match[i];
            for(int k=0;k<=2;k++)
            for(int l=0;l<=2;l++)
            for(int p=0;p<=2;p++)
            for(int q=0;q<=2;q++)
            {
                if(p==q&&(p!=0)) continue;
                dp[i][j][k][l]=(dp[i][j][k][l]+dp[i][t][k][p]*dp[t+1][j][q][l])%mod;
            }
        }

Let's talk about how to initialize. First, we need to initialize the interval with interval length of 1, that is

for(int i=1;i<=length;i++)
    for(int j=0;j<=2;j++)
    for(int k=0;k<=2;k++)
        if(j&k==0&&(j|k)) dp[i][i][j][k]=1;

Set the number of schemes to 1 as long as it is legal

Finally, let's talk about the answer and understand the meaning of dp array. This is relatively simple, that is, add dp [1] [length] [i] [J] (0 < = I, J < = 2)

The code is attached below:

 

#include<cstdio>
#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
#include<map>
#include<cmath>
#include<queue>
using namespace std;
const int N=703,mod=1e9+7;
char s[N];
int S[N],tt;
int match[N];//match[i] record the position of parentheses that match I 
long long dp[N][N][3][3];
void init(int len)
{
	for(int i=1;i<=len;i++)
	{
		if(s[i]=='(') S[++tt]=i;
		else
		{
			int t=S[tt--];
			match[i]=t;
			match[t]=i;
		}
	}
}
int main()
{
	scanf("%s",s+1);
	int length=strlen(s+1);
	init(length);
	for(int i=1;i<=length;i++)
	for(int j=0;j<=2;j++)
	for(int k=0;k<=2;k++)
		if(j&k==0&&(j|k)) dp[i][i][j][k]=1;
	for(int len=2;len<=length;len++)
	for(int i=1;i+len-1<=length;i++)
	{
		int j=i+len-1;
		if(match[i]==j)
		{
			if(len==2)
			{
				dp[i][j][0][1]=dp[i][j][0][2]=1;
				dp[i][j][1][0]=dp[i][j][2][0]=1;
				continue;
			}
			for(int k=0;k<=2;k++)
			for(int l=0;l<=2;l++)
			{
				if(l!=1) dp[i][j][0][1]=(dp[i][j][0][1]+dp[i+1][j-1][k][l])%mod;
				if(l!=2) dp[i][j][0][2]=(dp[i][j][0][2]+dp[i+1][j-1][k][l])%mod;
				if(k!=1) dp[i][j][1][0]=(dp[i][j][1][0]+dp[i+1][j-1][k][l])%mod;
				if(k!=2) dp[i][j][2][0]=(dp[i][j][2][0]+dp[i+1][j-1][k][l])%mod;
			}
		}
		else//match[i]!=j
		{
			int t=match[i];
			for(int k=0;k<=2;k++)
			for(int l=0;l<=2;l++)
			for(int p=0;p<=2;p++)
			for(int q=0;q<=2;q++)
			{
				if(p==q&&(p!=0)) continue;
				dp[i][j][k][l]=(dp[i][j][k][l]+dp[i][t][k][p]*dp[t+1][j][q][l])%mod;
			}
		}
	}
	long long ans=0;
	for(int i=0;i<=2;i++)
	for(int j=0;j<=2;j++)
		ans=(ans+dp[1][length][i][j])%mod;
	printf("%lld",ans);
	return 0;
}

Topics: Dynamic Programming