设 表示前 项 , 分别以 为结尾的 最长战胜序列 长度为 的方案数,
枚举状态, 转移, 总复杂度 .
可以发现 结尾的 最长上升序列 去掉 后得到长度为 的以 序列结尾的序列,
即 , 同理 , ,可得 , .
于是设 表示前 项, 分别以 为结尾的 最长战胜序列 长度为 的方案数, 转移即可, 时间复杂度 .
使用状态去更新状态, 注意在 变化时, 也要随着变化 .
#include<bits/stdc++.h>
#define reg register
const int maxn = 2005;
const int mod = 998244353;
int read(){
char c;
int s = 0, flag = 1;
while((c=getchar()) && !isdigit(c))
if(c == '-'){ c = getchar(), flag = -1; break ; }
while(isdigit(c)) s = s*10 + c-'0', c = getchar();
return s * flag;
}
int N;
int Ans[maxn];
int F[maxn][maxn][5][5];
bool vis[maxn][3];
char Smp[5];
int main(){
N = read();
for(reg int i = 1; i <= N; i ++){
scanf("%s", Smp);
int len = strlen(Smp);
for(reg int j = 0; j < len; j ++) vis[i][Smp[j]-'0'] = 1;
}
F[0][0][2][2] = 1;
for(reg int i = 0; i < N; i ++)
for(reg int j = 0; j <= i; j ++)
for(reg int a = 0; a <= 4; a ++)
for(reg int b = 0; b <= 4; b ++){
if(j+a-2 < 0 || j+b-2 < 0 || !F[i][j][a][b]) continue ;
int len_1 = j+a-2, len_2 = j+b-2;
if(vis[i+1][0]){
int nl = std::max(j, len_2+1);
int &t = F[i+1][nl][len_1-nl+2][len_2-nl+2];
t = (t + F[i][j][a][b]) % mod;
}
if(vis[i+1][1]){
int nl = std::max(j+1, len_1);
int &t = F[i+1][j][nl-j+2][b];
t = (t + F[i][j][a][b]) % mod;
}
if(vis[i+1][2]){
int nl = std::max(len_2, len_1+1);
int &t = F[i+1][j][a][nl-j+2];
t = (t + F[i][j][a][b]) % mod;
}
}
for(reg int i = 0; i <= N; i ++)
for(reg int a = 0; a <= 4; a ++)
for(reg int b = 0; b <= 4; b ++){
int t = std::max(i, std::max(i+a-2, i+b-2));
printf("%d
", F[N][i][a][b]);
Ans[t] = (Ans[t] + F[N][i][a][b]) % mod;
}
for(reg int i = 1; i <= N; i ++) printf("%d ", Ans[i]);
return 0;
}