0w1

CF 629C Famil Door and Brackets ( DP )

dp( a, b ) = the number of combinations, having a characters of valid prefix bracket sequence, and the opening bracket - closing = b
dp2( a, b ) = the number of combinations, having a characters of valid suffix bracket sequence, and the closing bracket - opening = b
i = number of characters in left string, j = number of characters in right string
op_cl = opening brackets - closing brackets in string s
mxcl_op = max of ( closing brackets - opening brackets ) in prefix( s )
The answer would be
SUM( dp[ i ][ k ] * dp2[ j ][ k + op_cl ] Ɐ i ≤ n - m & k ≥ mxcl_op )
Notice that dp() and dp2() do actually give the same, so pre-calculating either of them will do fine.

#include <bits/stdc++.h>
using namespace std;
const int MAXN_M = 2000 + 2;
const int MAXM = 1e5 + 5;
const int MAXN = 1e5 + 5;
const int MOD = 1e9 + 7;
typedef long long ll;
const ll INF = MOD + MOD;

int n, m;
string s;

ll dp[MAXN_M][MAXN_M];
void solve(){
    dp[0][0] = 1;
    for(int i = 0; i < 2000; ++i)
        for(int j = 0; j <= 2000; ++j){
            if( j - 1 >= 0 )
                ( dp[i + 1][j - 1] += dp[i][j] ) %= MOD;
            if( j + 1 <= 2000 )
                ( dp[i + 1][j + 1] += dp[i][j] ) %= MOD;
        }
    int op_cl = 0, mxcl_op = 0;
    for(int i = 0; i < m; ++i){
        if( s[ i ] == '(' ) ++op_cl;
        else --op_cl;
        mxcl_op = max<int>( mxcl_op, -op_cl );
    }
    ll ans = 0;
    for(int i = 0; i <= n - m; ++i){
        int j = n - m - i;
        for(int x = 0; x + mxcl_op <= 2000 && x + op_cl + mxcl_op <= 2000; ++x)
            ( ans += dp[i][x + mxcl_op] * dp[j][x + op_cl + mxcl_op] ) %= MOD;
    }
    ans %= MOD; ans += MOD; ans %= MOD;
    cout << ans << endl;
}

int main(){
    ios::sync_with_stdio(false);
    cin >> n >> m;
    cin >> s;
    solve();
    return 0;
}