CodeForces 1015F - Bracket Substring (KMP + dp)

題目鏈接

題意:

給你一個括號序列 ss 和一個數 nn ,讓你求出長度爲 2n2 * n 並且 ss 是最後串裏面的一個子串的合法括號序列有多少種。mod(1e9+7)mod (1e9 + 7)

參考 blogblog

分析:

先確定 dp[i][j][k]dp[i][j][k] 表示最後的串到第 ii 位,後綴匹配到長度爲 jj 的原串,有 kk 個未匹配的左括號的方案數有多少個。

爲什麼要這樣定義狀態呢,如果只是單純地定義 dp[i][k]dp[i][k] 的話,你不能夠確定這些串裏面是否含有 ss(感覺是廢話)。

那麼轉移就是 dp[i][j][k]dp[i][j][k] +=+= xdp[i1][k][x][()]\sum_{x}^{所有可能的後綴情況} dp[i - 1][k][x][看當前爲是 '(' 還是 ')',來決定]

但是這樣的轉移好像很麻煩,我們換成

dp[i][(][k+1]dp[i][當前位填'('後對應的原串後綴長度][k + 1] +=+= dp[i1][j][k]dp[i - 1][j][k]
dp[i][)][k]dp[i][當前位填')'後對應的原串後綴長度][k] +=+= dp[i1][j][k+1]dp[i - 1][j][k + 1]

是不是感覺很簡單,然後這個 當前位填 ‘(’ or ‘)’ 後對應的原串後綴長度 可以用 KMPKMPnextnext 數組來優化,我直接預處理出來一個數組 to[x][i]to[x][i] 表示當前串後綴已經和原串匹配了長度 xx ,接下來填 (‘(’ (i=0)(i = 0))‘)’ (i=1)(i = 1) 後,後綴和原串對應的匹配長度。然後就可以愉快的 dpdp 了。

當匹配到長度和原串相同時,就直接轉移到 lenlen 統計答案。

最後答案就是 dp[2n][len][0]dp[2 * n][len][0]

代碼:

#include <bits/stdc++.h>
#include <ext/rope>
using namespace __gnu_cxx;
using namespace std;
#define mst(a,b) memset(a,b,sizeof(a))
#define ALL(x) x.begin(),x.end()
#define pii pair<int, int>
#define debug(a) cout << #a": " << a << endl;
#define eularMod(a, b) a < b ? a : a % b + b
inline int lowbit(int x){ return x & -x; }
typedef long long LL;
typedef unsigned long long ULL;
const int N = 1e5 + 10;
const long long mod = 1000000007;
const int INF = 0x3f3f3f3f;
const long long LINF = 0x3f3f3f3f3f3f3f3fLL;
const double PI = acos(-1.0);
const double eps = 1e-6;

char s[205];
int n;
int nex[205];
int to[205][2];
int dp[205][205][205];

int main() {
#ifdef purple_bro
    freopen("in.txt", "r", stdin);
//    freopen("out.txt","w",stdout);
#endif
    scanf("%d%s", &n, s);

    n <<= 1;

    int len = strlen(s);

    nex[0] = 0;
    nex[1] = 0;

    for (int i = 1; i < len; i++) {
        int tmp = nex[i];

        for (;tmp && s[tmp] != '(';)
            tmp = nex[tmp];

        to[i][0] = (s[tmp] == '(') ? tmp + 1 : 0;

        tmp = nex[i];

        for (;tmp && s[tmp] != ')';)
            tmp = nex[tmp];

        to[i][1] = (s[tmp] == ')') ? tmp + 1 : 0;

        int j = nex[i];

        for (;j && s[j] != s[i];)
            j = nex[j];

        nex[i + 1] = (s[i] == s[j]) ? j + 1 : 0;
    }

    for (int i = 1; i <= n; i++) {
        if (i == 1) {
            if (s[0] == '(')
                dp[i][1][1] = 1;
            else
                dp[i][0][1] = 1;
            continue;
        }

        for (int j = 0; j <= len && j < i; j++) {
            for (int k = 0; k < i; k++) {
                if (j < len) {
                    if (s[j] == '(')
                        (dp[i][j + 1][k + 1] += dp[i - 1][j][k]) %= mod;
                    else 
                        (dp[i][to[j][0]][k + 1] += dp[i - 1][j][k]) %= mod;
                        
                    if (s[j] == ')')
                        (dp[i][j + 1][k] += dp[i - 1][j][k + 1]) %= mod;
                    else 
                        (dp[i][to[j][1]][k] += dp[i - 1][j][k + 1]) %= mod;
                } else {
                    (dp[i][j][k + 1] += dp[i - 1][j][k]) %= mod;
                    (dp[i][j][k] += dp[i - 1][j][k + 1]) %= mod;
                    //只轉移到 len
                }
            }
        }
    }

    printf("%d\n", dp[n][len][0]);

    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章