KMP+dp Codeforces346B Lucky Common Subsequence

传送门:点击打开链接

题意:告诉你A,B,C,求A和B的最长公共子序列,并且C不是最长公共子序列的子串

思路:先求C的Next数组,利用Next数组来完成状态的转移。

而且,用KMP来优化的dp,通常都是往后更新的写法。

对于打印路径,我们能用DFS来完成,这里有个我觉得很不错的写法,就是直接利用状压,来保存数字,感觉这样可以避免写一个结构体,方便的多

然后dp部分,就是在求最长公共子序列的基础上,再增加1维,来表示公共子序列最后一个字符是在C串的哪一个状态。

然后就是DFS在什么地方输出,应该在转移的路上增加了值时,说明在这个地方更新了答案,那时才输出。

#include <map>
#include <set>
#include <cmath>
#include <ctime>
#include <stack>
#include <queue>
#include <cstdio>
#include <cctype>
#include <string>
#include <vector>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <algorithm>
#include <functional>
#define fuck(x) cout<<"["<<x<<"]"
#define FIN freopen("input.txt","r",stdin)
#define FOUT freopen("output.txt","w+",stdout)
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;

const int MX = 1e2 + 5;
const int INF = 0x3f3f3f3f;

int Next[MX];
char A[MX], B[MX], C[MX];
int dp[MX][MX][MX], pre[MX][MX][MX];
void GetNext(char S[]) {
    Next[0] = 0;
    for(int i = 1; S[i]; i++) {
        int j = Next[i - 1];
        while(j && S[i] != S[j]) j = Next[j - 1];
        Next[i] = S[i] == S[j] ? j + 1 : 0;
    }
}
int get(int i, int j, int k) {
    return (i << 16) + (j << 8) + k;
}
void DFS(int id) {
    int i = id >> 16, j = id >> 8 & 0xff, k = id & 0xff;
    id = pre[i][j][k];
    int ni = id >> 16, nj = id >> 8 & 0xff, nk = id & 0xff;
    if(!i && !j) return;
    DFS(id);

    if(dp[i][j][k] - dp[ni][nj][nk] == 1) printf("%c", A[ni]);
}
int main() {
    //FIN;
    scanf("%s%s%s", A, B, C);
    int l1 = strlen(A), l2 = strlen(B), l3 = strlen(C);
    GetNext(C);

    memset(dp, -INF, sizeof(dp));
    for(int i = 0; i < l1; i++) {
        for(int j = 0; j < l2; j++) dp[i][j][0] = 0;
    }

    for(int i = 0; i <= l1; i++) {
        for(int j = 0; j <= l2; j++) {
            for(int k = 0; k < l3; k++) {
                if(dp[i + 1][j][k] < dp[i][j][k]) {
                    dp[i + 1][j][k] = dp[i][j][k];
                    pre[i + 1][j][k] = get(i, j, k);
                }
                if(dp[i][j + 1][k] < dp[i][j][k]) { 
                    dp[i][j + 1][k] = dp[i][j][k];
                    pre[i][j + 1][k] = get(i, j, k);
                }
                if(A[i] == B[j]) {
                    int w = k + 1;
                    while(w && A[i] != C[w]) w = Next[w - 1];
                    w = A[i] == C[w] ? w + 1 : 0;
                    if(dp[i + 1][j + 1][w] < dp[i][j][k] + 1) {
                        dp[i + 1][j + 1][w] = dp[i][j][k] + 1;
                        pre[i + 1][j + 1][w] = get(i, j , k);
                    }
                }
            }
        }
    }

    int ans = 0, id;
    for(int i = 0; i < l3; i++) {
        if(dp[l1][l2][i] > ans) {
            ans = dp[l1][l2][i];
            id = get(l1, l2, i);
        }
    }
    if(!ans) printf("0\n");
    else DFS(id);
    return 0;
}


你可能感兴趣的:(KMP+dp Codeforces346B Lucky Common Subsequence)