Codeforces 347D - Lucky Common Subsequence

给出两个长 100 的字符串 a ,b。再额外给出一个长 100 的字符串 virus 。询问 a b最长的没有字串是 virus 的公共子序列。输出这个子序列。


在经典的 LCS dp 解法上再加一维,记录当前的最长公共子序列匹配 virus 的长度。

第三维转移可以用 KMP 或者 AC 自动机。

#include<bits/stdc++.h>
using namespace std;
const int maxn = 112,maxLen = 26;

int toid(char c){ return c - 'A'; }
queue<int> Q;

struct acam{
    int nex[maxn][maxLen],fail[maxn];
    int cnt[maxn];
    int _cnt,root;
    int newNode(){
        memset(nex[_cnt],fail[_cnt] = -1,sizeof(nex[_cnt]));
        cnt[_cnt] = 0;
        return _cnt++;
    }
    void init(){
        _cnt = 0;
        root = newNode();
    }
    void insert(char *arr){
        int st = root;
        for(int i=0;arr[i];i++){
            int & stx = nex[st][toid(arr[i])];
            if(stx == -1) stx = newNode();
            st = stx;
        }
        cnt[st]++;
        // update cnt
    }
    void build(){
        while(Q.empty()==false) Q.pop();
        fail[root] = root;
        int st;
        for(int i=0;i<maxLen;i++){
            if((st = nex[root][i]) != -1){
                fail[st] = root;
                Q.push(st);
            }
            else nex[root][i] = root;
        }
        while(Q.empty()==false){
            st = Q.front(),Q.pop();
            for(int i=0;i<maxLen;i++){
                if(nex[st][i] != -1){
                    int fst = fail[st],son = nex[st][i];
                    while(fst != root && nex[fst][i] == -1)
                        fst = fail[fst];
                    fail[son] = nex[fst][i] == -1 ? root : nex[fst][i];
                    Q.push(son);
                }
                else{
                    nex[st][i] = nex[fail[st]][i];
                }
            }
        }
    }
    void out(){
        for(int i = 0; i<_cnt;i++){
            printf("id = %d : ",i);
            for(int j = 0;j<maxLen;j++){
                if(nex[i][j] != 0){
                    printf("%c -> %d ",j + 'A',nex[i][j]);
                }
            }
            puts("");
        }
    }
}acam;

char a[maxn],b[maxn],vair[maxn];
string dp[maxn][maxn][maxn];

string smax(string a,string b){
    if(a.size() > b.size())
        return a;
    return b;
}

int main(){
    acam.init();
    scanf("%s %s %s",a+1,b+1,vair);
    acam.insert(vair);
    acam.build();
    int n = strlen(a+1),m = strlen(b+1);
    int vsiz = strlen(vair);
    for(int i = 0;i<=n;i++){
        for(int j = 0;j <= m;j++){
            for(int k = 0; k <= vsiz; k++){
                dp[i][j][k] = "";
            }
        }
    }
    for(int i = 1;i<=n;i++){
        for(int j = 1;j<=m;j++){
            for(int k = 0 ; k < vsiz;k++){
                dp[i][j][k] = smax(dp[i][j][k],dp[i-1][j][k]);
                dp[i][j][k] = smax(dp[i][j][k],dp[i][j-1][k]);
                if(a[i] == b[j]){
                    int x = a[i] - 'A';
                    int kx = acam.nex[k][x];
                    dp[i][j][kx] = smax(dp[i][j][kx],dp[i-1][j-1][k]+string(1,a[i]));
                }
            }
        }
    }
    string ans = "";
    for(int i = 0;i < vsiz;i++){
        ans = smax(ans,dp[n][m][i]);
    }
    if(ans == "") ans = "0";
    printf("%s\n",ans.c_str());
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值