Lightoj1577【數位DP】

題意:
求兩字符串LCS的個數。
思路:
LCS的狀態轉移應用吧,如果當前字符種類相同的,dp[pos1][pos2]肯定是最長的。
根據求LCS的DP狀態轉移回溯,如果枚舉那些位置往前回溯肯定GG。
考慮對於兩個字符串每個位置上的字符,枚舉字符種類,那麼如果當前字符種類相同的,dp[pos1][pos2]肯定是最長的,那麼就可以往前再找。
所以預處理一下對於每個位置,每個字符之前離當前位置最近的位置。
然後就可以直接查詢了,一個數位DP就這樣了。


然後對於數位DP如果理解成那種數字上的DP
好像確實顯得好狹隘啊,那個 當 limit == false 才能記錄DP值,只是DP的一個約束罷了,數位DP的好在於能枚舉每一位的信息,然後記錄當前位至以後的信息,從而降低複雜度。(盲目分析.jpg)

//#pragma comment(linker, "/STACK:102400000,102400000")
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
#include <time.h>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
#define lson num<<1, Left, Mid
#define rson num<<1|1, Mid+1, Right
#define mem(a, b) memset(a, b, sizeof(a))
typedef pair<int,int> PII;

const int Mod = 1000007;
const int Maxn = 1e3 + 10;

char s1[Maxn], s2[Maxn];
int n, m;
int dp[Maxn][Maxn];
int ans[Maxn][Maxn];
int lx[Maxn][30], ly[Maxn][30];

void Maxlen(){
    for(int i=0;i<=n;i++)
    for(int j=0;j<=m;j++) dp[i][j] = 0;
    for(int i=0;i<26;i++) lx[0][i] = ly[0][i] = 0;

    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            if(s1[i] == s2[j]) dp[i][j] = dp[i-1][j-1] + 1;
            else dp[i][j] = max(dp[i-1][j], dp[i][j-1]);
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=0;j<26;j++){
            lx[i][j] = lx[i-1][j];
            if((j+'a') == s1[i]) lx[i][j] = i;
        }
    }
    for(int i=1;i<=m;i++){
        for(int j=0;j<26;j++){
            ly[i][j] = ly[i-1][j];
            if((j+'a') == s2[i]) ly[i][j] = i;
        }
    }
}

int DFS(int p1, int p2, int len){
    if(len <= 0) return 1;
    if(ans[p1][p2] != -1) return ans[p1][p2];
    int res = 0;
    if(p1 > 0 && p2 > 0){
        for(int i=0;i<26;i++){
            int t1 = lx[p1][i];
            int t2 = ly[p2][i];
            if(dp[t1][t2] == len){
                res = res + DFS(t1-1, t2-1, len-1);
                res = res % Mod;
            }
        }
    }
    ans[p1][p2] = res;
    return res;
}

int solve(){
    memset(ans, -1, sizeof(ans));
    return DFS(n, m, dp[n][m]);
}

int main(){
    int T, cas = 1;
    scanf("%d", &T);
    while(T--){
        scanf("%s%s", s1+1, s2+1);
        n = strlen(s1+1);
        m = strlen(s2+1);
        Maxlen();
        printf("Case %d: %d\n", cas++, solve());
    }
    return 0;
}

/*
4
acbd
acbd
vnvn
vn
ab
ba
xyz
abc
*/
發佈了799 篇原創文章 · 獲贊 125 · 訪問量 38萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章