战 胜 序 列 战胜序列 战胜序列
正 解 部 分 \color{red}{正解部分} 正解部分
设
F
[
i
,
a
,
b
,
c
]
F[i, a, b, c]
F[i,a,b,c] 表示前
i
i
i 项 , 分别以
0
,
1
,
2
0,1,2
0,1,2 为结尾的 最长战胜序列 长度为
a
,
b
,
c
a, b, c
a,b,c 的方案数,
枚举状态,
O
(
3
)
O(3)
O(3) 转移, 总复杂度
O
(
N
4
)
O(N^4)
O(N4) .
可以发现
0
0
0 结尾的 最长上升序列 去掉
0
0
0 后得到长度为
b
−
1
b-1
b−1 的以
2
2
2 序列结尾的序列,
即
b
≥
a
−
1
b \geq a-1
b≥a−1, 同理
c
≥
b
−
1
c \geq b-1
c≥b−1,
a
≥
c
−
1
a \geq c-1
a≥c−1 ,可得
∣
b
−
a
∣
≤
2
|b-a| \le 2
∣b−a∣≤2,
∣
c
−
a
∣
≤
2
|c-a| \le 2
∣c−a∣≤2 .
于是设 F [ i , a , b , c ] F[i, a, b, c] F[i,a,b,c] 表示前 i i i 项, 分别以 0 , 1 , 2 0,1,2 0,1,2 为结尾的 最长战胜序列 长度为 a , a + b − 2 , a + c − 2 a, a+b-2, a+c-2 a,a+b−2,a+c−2 的方案数, 转移即可, 时间复杂度 O ( N 2 ) O(N^2) O(N2) .
实 现 部 分 \color{red}{实现部分} 实现部分
使用状态去更新状态, 注意在 a a a 变化时, b , c b,c b,c 也要随着变化 .
#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\n", 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;
}