【题目链接】
【思路要点】
- 考虑最长公共子序列的DP数组,它的每一行只有\(O(K)\)个数,并且相邻两数只差在1以内。
- 因此,我们可以将每一行压为一个在\(2^K\)以内的二进制数。
- 预处理每个状态的后续状态,简单DP即可。
- 需要滚动数组,时间复杂度\(O(N*2^K)\)。
【代码】
#include<bits/stdc++.h> using namespace std; const int MAXK = 20; const int MAXN = 1005; const int MAXS = 32768; const int P = 1e9 + 7; template <typename T> void chkmax(T &x, T y) {x = max(x, y); } template <typename T> void chkmin(T &x, T y) {x = min(x, y); } template <typename T> void read(T &x) { x = 0; int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; x *= f; } template <typename T> void write(T x) { if (x < 0) x = -x, putchar('-'); if (x > 9) write(x / 10); putchar(x % 10 + '0'); } template <typename T> void writeln(T x) { write(x); puts(""); } int n, m, bit[MAXK]; int dest[MAXS][3]; int dp[2][3][MAXS], ans[MAXK]; char st[MAXK]; void update(int &x, int y) { x += y; if (x >= P) x -= P; } int main() { read(n), read(m); scanf("\n%s", st + 1); for (int i = 1; i <= m; i++) bit[i] = 1 << (i - 1); dp[0][0][0] = 1; int goal = (1 << m) - 1; for (int s = 0; s <= goal; s++) { static int now[MAXK]; for (int i = 1; i <= m; i++) now[i] = now[i - 1] + ((bit[i] & s) != 0); static int res[MAXK]; for (int i = 1; i <= m; i++) { if (st[i] == 'N') res[i] = now[i - 1] + 1; else res[i] = max(res[i - 1], now[i]); dest[s][0] |= (res[i] - res[i - 1]) * bit[i]; } for (int i = 1; i <= m; i++) { if (st[i] == 'O') res[i] = now[i - 1] + 1; else res[i] = max(res[i - 1], now[i]); dest[s][1] |= (res[i] - res[i - 1]) * bit[i]; } for (int i = 1; i <= m; i++) { if (st[i] == 'I') res[i] = now[i - 1] + 1; else res[i] = max(res[i - 1], now[i]); dest[s][2] |= (res[i] - res[i - 1]) * bit[i]; } } for (int i = 1, now = 1, from = 0; i <= n; i++, swap(now, from)) { memset(dp[now], 0, sizeof(dp[now])); for (int s = 0; s <= goal; s++) { update(dp[now][1][dest[s][0]], dp[from][0][s]); update(dp[now][0][dest[s][1]], dp[from][0][s]); update(dp[now][0][dest[s][2]], dp[from][0][s]); update(dp[now][1][dest[s][0]], dp[from][1][s]); update(dp[now][2][dest[s][1]], dp[from][1][s]); update(dp[now][0][dest[s][2]], dp[from][1][s]); update(dp[now][1][dest[s][0]], dp[from][2][s]); update(dp[now][0][dest[s][1]], dp[from][2][s]); } } int now = n & 1; for (int i = 0; i <= 2; i++) for (int s = 0; s <= goal; s++) { int cnt = 0, tmp = s; while (tmp != 0) { cnt++; tmp -= tmp & -tmp; } update(ans[cnt], dp[now][i][s]); } for (int i = 0; i <= m; i++) writeln(ans[i]); return 0; }