战胜序列 [性质dp]

战胜序列



color{red}{正解部分}

F[i,a,b,c]F[i, a, b, c] 表示前 ii 项 , 分别以 0,1,20,1,2 为结尾的 最长战胜序列 长度为 a,b,ca, b, c 的方案数,
枚举状态, O(3)O(3) 转移, 总复杂度 O(N4)O(N^4) .

可以发现 00 结尾的 最长上升序列 去掉 00 后得到长度为 b1b-1 的以 22 序列结尾的序列,
ba1b geq a-1, 同理 cb1c geq b-1, ac1a geq c-1 ,可得 ba2|b-a| le 2, ca2|c-a| le 2 .

于是设 F[i,a,b,c]F[i, a, b, c] 表示前 ii 项, 分别以 0,1,20,1,2 为结尾的 最长战胜序列 长度为 a,a+b2,a+c2a, a+b-2, a+c-2 的方案数, 转移即可, 时间复杂度 O(N2)O(N^2) .


color{red}{实现部分}

使用状态去更新状态, 注意在 aa 变化时, b,cb,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
", 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;
}
原文地址:https://www.cnblogs.com/zbr162/p/11822403.html