F |LIS| = 3

https://atcoder.jp/contests/abc237/tasks/abc237_f
考虑用二分做最长上升子序列的数组的表示方法
\(f[i][j][k][l]表示从前i个选,长度为1的最长上升子序列中最小的数为j,长度为2的最长上升子序列中最后一个数最小的数为k,长度为3的最长上升子序列中最后一个数最小的数为l的方案数\)
由于可选的最大的数为\(m\),所以我们用\(m+1\)表示不存在的情况

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1010;
const int MOD = 998244353;
int n, m;
int f[1010][12][12][12];
signed main() {
    cin >> n >> m;
    f[0][m + 1][m + 1][m + 1] = 1;
    for (int i = 1; i <= n; i ++ ) {
        for (int j = 0; j <= m + 1; j ++ ) {
            for (int k = j; k <= m + 1; k ++ ) {
                for (int l = k; l <= m + 1; l ++ ) {
                    if (f[i - 1][j][k][l]) {
                        for (int x = 1; x <= m; x ++ ) {
                            vector<int> c(10);
                            c[1] = j, c[2] = k, c[3] = l, c[4] = m + 1;
                            int pos = 0;
                            for (int y = 1; y <= 3; y ++ )
                                if (c[y] != m + 1)
                                    pos = y;
                            if (x > c[pos])
                                c[++ pos] = x;
                            else {
                                int p = 0;
                                for (int y = 1; y <= pos; y ++ )
                                    if (x > c[y])
                                        p = y;
                                c[p + 1] = x;
                            }
                            if (pos <= 3) 
                                f[i][c[1]][c[2]][c[3]] = (f[i][c[1]][c[2]][c[3]] + f[i - 1][j][k][l]) % MOD;
                        }
                    }
                }
            }
        }
    }
    int ans = 0;
    for (int i = 1; i <= m; i ++ )
        for (int j = i + 1; j <= m; j ++ )
            for (int k = j + 1; k <= m; k ++ )
                ans = (ans + f[n][i][j][k]) % MOD;
    cout << ans << endl;
    return 0;
}
posted @ 2022-02-07 11:42  Angels_of_Death  阅读(56)  评论(0)    收藏  举报