UVa 10069 - Distinct Subsequences

dp+大数加法。

设母串的长度为 j, 子串的长度为 i,我们要求的就是长度为 i 的字串在长度为 j 的母串中出现的次数。

(1)若母串的最后一个字符与子串的最后一个字符不同,则长度为 i 的子串在长度为 j 的母串中出现的次数就是母串的前 j - 1 个字符中子串出现的次数,即 str[i][j] = str[i][j - 1];

(2)若母串的最后一个字符与子串的最后一个字符相同,那么除了前 j - 1 个字符出现子串的次数外,还要加上子串的前 i - 1 个字符在母串的前 j - 1 个字符中出现的次数(再加上当前相等的这个字符其长度就可以凑成完整的字串长度),即 str[i][j] = str[i][j - 1] + str[i - 1][j - 1]。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
char dp[101][10001][102], str1[10002], str2[102];
void Add(char *c, char *a, char *b)
{
    int len_a = strlen(a);
    int len_b = strlen(b);
    int len_c = max(len_a, len_b);
    memset(c, 0, (len_c+2)*sizeof(c[0]));
    for(int i=len_a-1, j=len_c; i>=0; --i, --j)
        c[j] += a[i] - '0';
    for(int i=len_b-1, j=len_c; i>=0; --i, --j)
        c[j] += b[i] - '0';
    for(int i=len_c; i>0; c[i]+='0', --i)
            if(c[i] > 9)
            {
                c[i] -= 10;
                ++c[i-1];
            }

    if(!c[0])
    {
        for(int i=0; i<len_c; ++i)
            c[i] = c[i+1];
        c[len_c] = 0;
    }
    else
        c[0] = '1';
}
int main()
{
#ifdef test
    freopen("input.txt", "r", stdin);
#endif
    int num;
    scanf("%d", &num);
    while(num--)
    {
        scanf("%s%s", str1, str2);
        int len1 = strlen(str1), len2 = strlen(str2);
        for(int i=0; i<=len1; ++i)
            strcpy(dp[0][i], "1");

        for(int i=1; i<=len2; ++i)
            {
                strcpy(dp[i][i-1], "0"); // 此语句可有可无,因为dp[i][i-1]本身为‘\0’,不影响加的过程
                for(int j=i; j<=len1; ++j)
                {
                    if(str1[j-1] == str2[i-1])
                        Add(dp[i][j], dp[i][j-1], dp[i-1][j-1]); //dp[i][j] = dp[i][j-1] + dp[i-1][j-1];
                    else
                        strcpy(dp[i][j], dp[i][j-1]); //dp[i][j] = dp[i][j-1];
                }
            }

        printf("%s\n", dp[len2][len1]);
    }
    return 0;
}


你可能感兴趣的:(UVa 10069 - Distinct Subsequences)