题目:
Petya遇到了一个关于括号序列的问题: 给定一个字符串S,它代表着正确的括号序列,即(“(”)与 (“)”)是匹配的。例如:“(())()” 和 “()”是正确的,“)()”与“(()”则不是正确的。 在正确的括号序列中,一个左边的括号一定是匹配一个右边的括号(反之亦然)。例如,在下图中,第 3 个括号匹配第 6 个括号,第 4 个括号匹配第 5 个括号。
现在你需要对一个正确的括号序列做涂色操作,严格满足以下三个条件:
1、每个括号要么不涂色,要么涂红色,要么涂蓝色。
2、一对匹配的括号需要且只能将其中一个涂色。
3、相邻的括号不能涂上同一种颜色(但是可以都不涂颜色)。
求:给整个括号序列涂上颜色的方案数,答案可能比较大,对 1000000007 取模。
输入1:
(())
输出1:
12
输入2:
(()())
输出2:
40
输入3:
()
输出3:
4
题解:
首先由于是括号,我们需要知道它的左括号下标及右括号下标,存入数组方便后面用,方法是用栈,详细见代码:
void p() {
for(int i = 0;i < n; i++) {
if(a[i] == '(') {
s.push(i);//右括号输入进去
}
else{
b[i] = s.top();//遇到对应左括号弹出,再对下标保存
b[s.top()] = i;
s.pop();
}
}
return;
}
首先这道题的状态很不一样,令dp[i][j][k][l]为i括号取k种类颜色,和j括号取l种类颜色的方案总数。dp[i][j][k][l]应等于:
1.i+1==j(i括号与j括号相邻)
取法为一个无色一个颜色二选一
dp[i][j][1][0] = 1;
dp[i][j][0][1] = 1;
dp[i][j][2][0] = 1;
dp[i][j][0][2] = 1;
2.若b[i] == j(当i括号与j括号对应时):
首先求得元区间dp[i + 1][j - 1][k][l]的方案数, 用来求一个无色,一个随便取方式比如:dp[i][j][0][1],再加上dp[i + 1][j - 1][k][l] (注意l不能为1,因为若为1,则j-1号位为一号颜色,而j号位又是一号颜色所以相邻两个重复,舍去),其它三个完全同理思考,见代码:
if(j != 1) {
dp[qi][zhong][0][1] += dp[qi + 1][zhong - 1][i][j];
dp[qi][zhong][0][1] %= mod;
}
if(i != 1) {
dp[qi][zhong][1][0] += dp[qi + 1][zhong - 1][i][j];
dp[qi][zhong][1][0] %= mod;
}
if(j != 2) {
dp[qi][zhong][0][2] += dp[qi + 1][zhong - 1][i][j];
dp[qi][zhong][0][2] %= mod;
}
if(i != 2) {
dp[qi][zhong][2][0] += dp[qi + 1][zhong - 1][i][j];
dp[qi][zhong][2][0] %= mod;
}
3.若b[i] != j(当i括号与j括号不对应时)
dp[i][j][k][l]+=(i ~ s[i]对应的右括号下标即b[i]的任意颜色组合方案数) * (s[i]对应的右括号下标的下一位即b[i] + 1 ~ j的任意颜色组合方案数)
详细见代码:
for(int i = 0;i < 3; i++) {
for(int j = 0;j < 3; j++) {
for(int l = 0;l < 3; l++) {
for(int m = 0;m < 3; m++) {
if(l != m || l == 0 || m == 0) {
dp[qi][zhong][i][j] += (dp[qi][k][i][l] * dp[k + 1][zhong][m][j]) % mod;
dp[qi][zhong][i][j]%=mod;
}
}
}
}
}//注意为什么是四重,因为为了让两括号颜色错开(不相同),所以用了四重
代码:
#include <iostream>
#include <cstdio>
#include <stack>
#include <cstring>
using namespace std;
#define mod 1000000007
long long dp[705][705][3][3];
int b[705], n, sum = 0;
char a[705];
stack<int>s;
void p() {
for(int i = 0;i < n; i++) {
if(a[i] == '(') {
s.push(i);
}
else{
b[i] = s.top();
b[s.top()] = i;
s.pop();
}
}
return;
}
void d(int qi, int zhong) {
if(qi + 1 == zhong) {
dp[qi][zhong][1][0] = 1;
dp[qi][zhong][0][1] = 1;
dp[qi][zhong][2][0] = 1;
dp[qi][zhong][0][2] = 1;
return;
}
if(b[qi] == zhong) {
d(qi + 1, zhong - 1);
for(int i = 0;i < 3; i++) {
for(int j = 0;j < 3; j++) {
if(j != 1) {
dp[qi][zhong][0][1] += dp[qi + 1][zhong - 1][i][j];
dp[qi][zhong][0][1] %= mod;
}
if(i != 1) {
dp[qi][zhong][1][0] += dp[qi + 1][zhong - 1][i][j];
dp[qi][zhong][1][0] %= mod;
}
if(j != 2) {
dp[qi][zhong][0][2] += dp[qi + 1][zhong - 1][i][j];
dp[qi][zhong][0][2] %= mod;
}
if(i != 2) {
dp[qi][zhong][2][0] += dp[qi + 1][zhong - 1][i][j];
dp[qi][zhong][2][0] %= mod;
}
}
}
return;
}
int k = b[qi];
d(qi, k);
d(k + 1, zhong);
for(int i = 0;i < 3; i++) {
for(int j = 0;j < 3; j++) {
for(int l = 0;l < 3; l++) {
for(int m = 0;m < 3; m++) {
if(l != m || l == 0 || m == 0) {
dp[qi][zhong][i][j] += (dp[qi][k][i][l] * dp[k + 1][zhong][m][j]) % mod;
dp[qi][zhong][i][j]%=mod;
}
}
}
}
}
}
int main() {
scanf("%s", a);
n = strlen(a);
p();
d(0, n - 1);//由于字符串从0开始所以这里改成0~n-1
long long sum = 0;
for(int i = 0;i < 3; i++) {
for(int j = 0;j < 3; j++) {
sum = (sum + dp[0][n - 1][i][j]) % mod;//同上
}
}
printf("%lld", sum % mod);
return 0;
}