1 条题解

  • 0
    @ 2025-3-13 19:47:05

    基础代码

    在 1100 ms 波动

    #include <bits/stdc++.h>
    using namespace std;
    const int MAXN = 300;
    const int MOD = 998244353;
    int n;
    string s;
    // f[i][rg][rb][bg]
    // 前 i 个字符,有多少种方案可以使得除了已经消耗的还多了:
    // rg 个红绿左括号、rb 个红蓝左括号、bg 个 蓝绿左括号
    int now, nxt; // 滚动数组优化掉 f 第一维
    // 显然超过了一半的是左括号时就不用管了,后面不可能合法
    int f[2][MAXN / 2 + 5][MAXN / 2 + 5][MAXN / 2 + 5];
    
    // 让 a 在原本基础上增加 b,然后再对 MOD 取余
    void add(int &a, int &b)
    {
        a += b;
        if (a >= MOD)
            a -= MOD;
    }
    int main()
    {
        ios::sync_with_stdio(false);
        cin.tie(0);
        cin >> n;
        cin >> s;
    
        // 用填表法比较方便(有效状态推出后续状态)
        now = 0, nxt = 1;
        f[now][0][0][0] = 1; // 初始状态
        for (int i = 0; i <= n - 1; i++)
        {
            // 由 f[i(now)][][][] 填出 f[i+1(nxt)][][][]
            // 此时最多只会贡献出 i 个左括号
            // 此时也最多只需要 n-i 个左括号(不然右边就不可能消耗完)
            for (int rg = 0; rg <= min(i, n - i); rg++)
                for (int rb = 0; rb <= min(i, n - i); rb++)
                    for (int bg = 0; bg <= min(i, n - i); bg++)
                    {
                        if (s[i] != '(')
                        {
                            // 此时可以看作是 ),可以考虑是哪种颜色,来消耗对应颜色的左括号
                            if (rg > 0 && rb > 0)
                                add(f[nxt][rg - 1][rb - 1][bg], f[now][rg][rb][bg]);
                            if (rb > 0 && bg > 0)
                                add(f[nxt][rg][rb - 1][bg - 1], f[now][rg][rb][bg]);
                            if (rg > 0 && bg > 0)
                                add(f[nxt][rg - 1][rb][bg - 1], f[now][rg][rb][bg]);
                        }
                        if (s[i] != ')')
                        {
                            add(f[nxt][rg + 1][rb + 1][bg], f[now][rg][rb][bg]);
                            add(f[nxt][rg][rb + 1][bg + 1], f[now][rg][rb][bg]);
                            add(f[nxt][rg + 1][rb][bg + 1], f[now][rg][rb][bg]);
                        }
                    }
            // 滚动数组,并给下一层清空
            swap(now, nxt);
            for (int rg = 0; rg <= n / 2; rg++)
                for (int rb = 0; rb <= n / 2; rb++)
                    for (int bg = 0; bg <= n / 2; bg++)
                        f[nxt][rg][rb][bg] = 0;
        }
        cout << f[now][0][0][0];
        return 0;
    }
    

    加了些无解状态的优化,但是结果跑的似乎更慢了(

    #include <bits/stdc++.h>
    using namespace std;
    const int MAXN = 300;
    const int MOD = 998244353;
    int n;
    string s;
    int now, nxt;
    int f[2][MAXN / 2 + 5][MAXN / 2 + 5][MAXN / 2 + 5];
    
    void add(int &a, int &b)
    {
        a += b;
        if (a >= MOD)
            a -= MOD;
    }
    int main()
    {
        ios::sync_with_stdio(false);
        cin.tie(0);
        cin >> n;
        cin >> s;
    
        now = 0, nxt = 1;
        f[now][0][0][0] = 1;
        for (int i = 0; i <= n - 1; i++)
        {
            for (int rg = 0; rg <= min(i, n - i); rg++)
                for (int rb = 0; rb <= min(i, n - i); rb++)
                    // 三个相加的结果就是三种颜色括号数量的两倍,必然是偶数
                    for (int bg = (rg + rb) % 2; bg <= min(i, n - i); bg += 2)
                    {
                        // 如果当前状态不可能达成最终 rg, rb, bg 清空,那也不用管当前状态了
                        // 当前的左括号总数就是 (rg + rb + bg) / 2,当前都不行,更多左括号就更不行了
                        if ((rg + rb + bg) / 2 > n - i)
                            break;
                        if (s[i] != '(')
                        {
                            if (rg > 0 && rb > 0)
                                add(f[nxt][rg - 1][rb - 1][bg], f[now][rg][rb][bg]);
                            if (rb > 0 && bg > 0)
                                add(f[nxt][rg][rb - 1][bg - 1], f[now][rg][rb][bg]);
                            if (rg > 0 && bg > 0)
                                add(f[nxt][rg - 1][rb][bg - 1], f[now][rg][rb][bg]);
                        }
                        if (s[i] != ')')
                        {
                            add(f[nxt][rg + 1][rb + 1][bg], f[now][rg][rb][bg]);
                            add(f[nxt][rg][rb + 1][bg + 1], f[now][rg][rb][bg]);
                            add(f[nxt][rg + 1][rb][bg + 1], f[now][rg][rb][bg]);
                        }
                    }
            swap(now, nxt);
            for (int rg = 0; rg <= n / 2; rg++)
                for (int rb = 0; rb <= n / 2; rb++)
                    for (int bg = 0; bg <= n / 2; bg++)
                        f[nxt][rg][rb][bg] = 0;
        }
        cout << f[now][0][0][0];
        return 0;
    }
    
    • 1

    信息

    ID
    1793
    时间
    2000ms
    内存
    512MiB
    难度
    8
    标签
    (无)
    递交数
    65
    已通过
    10
    上传者