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万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章