Codeforces Round #501 (Div. 3) F(动态规划)

大致题意:
给定一个数 n 与一个字符串 s
问有多少个长度为 2 n 的字符串包含 s
10 9 + 7 取模
n <= 100 | s | <= 200


实际上不是特别难啊….但是谷歌翻译又一次 g a n k 了我
我以为是包含一个子序列 可以不连续,磕不出来
连续子串就好做了
f i , j , k , l 表示已经放了 i 个左右括号,未匹配的左括号有 j 个,当前字符串有长度为 k 的后缀与 s 的前缀匹配, l 表示是否以及出现过连续字串 s
我们预处理出来 l e n [ i ] [ 0..1 ] 表示以及有 i 位与 s 从头匹配,加一个” ( ”或” ) ”之后能匹配的长度
f i , j , k , l 能转移到 f i + 1 , j + 1 , l e n [ k ] [ 0 ] , f | [ l e n [ k ] [ 0 ] == l e n ( s ) ]
f i + 1 , j 1. l e n [ k ] [ 1 ] , f | [ l e n [ k ] [ 1 ] == l e n ( s ) ]
答案就是 i = 1 | s | f 2 n , 0 , i , 1

#include <bits/stdc++.h>

using namespace std;

const int N = 203;
const int MOD = 1e9 + 7;

int n, ssz;
string s;
int len[N][2];
int dp[N][N][N][2];

int calc(const string &t) {
    int tsz = t.size();
    for (int i = tsz; i > 0; --i) {
        if (s.substr(0, i) == t.substr(tsz - i, i))
            return i;
    }
    return 0;
}

void add(int &a, int b) {
    a += b;
    if (a >= MOD)
        a -= MOD;
    if (a < 0)
        a += MOD;
}

int main() {
#ifdef _DEBUG
//  freopen("input.txt", "r", stdin);
//  freopen("output.txt", "w", stdout);
#endif

    cin >> n >> s;
    ssz = s.size();

    if (s[0] == '(')
        len[0][0] = 1;
    else
        len[0][1] = 1;

    string pref;
    int t = 0;
    for (int i = 0; i < ssz; ++i) {
        pref[++t] = s[i];
        pref[++t] = '(';
        len[i + 1][0] = calc(pref);
        t--;
        pref[++t] = ')';
        len[i + 1][1] = calc(pref);
        t--;
    }

    dp[0][0][0][0] = 1;
    for (int i = 0; i < 2 * n; ++i) {
        for (int j = 0; j <= n; ++j) {
            for (int pos = 0; pos <= ssz; ++pos) {
                for (int f = 0; f < 2; ++f) {
                    if (dp[i][j][pos][f] == 0) continue;
                    if (j + 1 <= n)
                        add(dp[i + 1][j + 1][len[pos][0]][f | (len[pos][0] == ssz)], dp[i][j][pos][f]);
                    if (j > 0)
                        add(dp[i + 1][j - 1][len[pos][1]][f | (len[pos][1] == ssz)], dp[i][j][pos][f]);
                }
            }
        }
    }

    int ans = 0;
    for (int i = 0; i <= ssz; ++i)
        add(ans, dp[2 * n][0][i][1]);

    cout << ans << endl;

    return 0;
}

猜你喜欢

转载自blog.csdn.net/a1035719430/article/details/81349726