Codeforces Round #343 (Div. 2) C

本文探讨了一种特定的括号匹配问题,通过将左括号视为1、右括号视为-1的方式,将问题转化为数值求解。使用动态规划方法预处理所有可能的状态,最终计算出使字符串变为有效括号序列的字符串对数量。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

As Famil Door’s birthday is coming, some of his friends (like Gabi) decided to buy a present for him. His friends are going to buy a string consisted of round brackets since Famil Door loves string of brackets of length n more than any other strings!

The sequence of round brackets is called valid if and only if:

the total number of opening brackets is equal to the total number of closing brackets;
for any prefix of the sequence, the number of opening brackets is greater or equal than the number of closing brackets.
Gabi bought a string s of length m (m ≤ n) and want to complete it to obtain a valid sequence of brackets of length n. He is going to pick some strings p and q consisting of round brackets and merge them in a string p + s + q, that is add the string p at the beginning of the string s and string q at the end of the string s.

Now he wonders, how many pairs of strings p and q exists, such that the string p + s + q is a valid sequence of round brackets. As this number may be pretty large, he wants to calculate it modulo 109 + 7.

Input
First line contains n and m (1 ≤ m ≤ n ≤ 100 000, n - m ≤ 2000) — the desired length of the string and the length of the string bought by Gabi, respectively.

The second line contains string s of length m consisting of characters ‘(’ and ‘)’ only.

Output
Print the number of pairs of string p and q such that p + s + q is a valid sequence of round brackets modulo 109 + 7.

Examples
input
4 1
(
output
4
input
4 4
(())
output
1
input
4 3
(((
output
0
Note
In the first sample there are four different valid pairs:

p = “(“, q = “))”
p = “()”, q = “)”
p = “”, q = “())”
p = “”, q = “)()”
In the second sample the only way to obtain a desired string is choose empty p and q.

In the third sample there is no way to get a valid sequence of brackets.

这个题看着题干能想想到这么一点
因为是括号匹配问题
所以要换成值来求
左括号是1有括号是-1
中间那一坨直接换成一个和就可以了
然后再两边放
来枚举种类,长度和和
这里要用dp预处理
dp[a][b] 这里的a是长度,b是和
存的就是长度
状态转移的原理也很简单
先预处理和尾b的时候
b可以从b+1和b-1这两种状态转移得到
是打表才看出来的规律…
具体原理…
会了再补

会了…
首先每一种状态都是所有的可能出现的情况
然后就会出现了只要在尾部加一个就够的情况
所以就可以这样递推了

#include <iostream>
#include <cmath>
#include <cstdio>
#include <algorithm>
#include <string>
using namespace std;
long long dp[2220][2220];
long long mo = 1e9 + 7;
int main()
{
#define int long long
    int n, m;
    dp[1][1] = 1;
    dp[0][0] = 1;
    for (int a = 2;a <= 2000;a++)
    {
        for (int b = 0;b <= a;b++)
        {
            if (b == 0)
            {
                dp[a][b] = dp[a - 1][b + 1]%mo;
                continue;
            }
            dp[a][b] = (dp[a - 1][b - 1] + dp[a - 1][b + 1]) % mo;
        }
    }
    cin >> n >> m;
    string q;
    cin >> q;
    int jsd = 0;
    int xx = 0;
    for (int a = 0;a < q.size();a++)
    {
        if (q[a] == '(')jsd++;
        else jsd--;
        xx = min(jsd, xx);
    }
    if (jsd == q.size() && jsd >= n / 2)
    {
        cout << 0 << endl;
        return 0;
    }
    int js = 0;
    for (int a = 0;a <= n - m;a++)
    {
        for (int b = 0;b <= a;b++)
        {
            if (xx + b >= 0 )
            {
                js = (js + dp[a][b] * dp[n - m - a][jsd + b]) % mo;
            }
        }
    }
    cout << js;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值