题目传送门

Uva变了,以后恐怕不能叫它Uva了……


第一问还是很简单的,直接求最长公共子序列的长度,那么这两个字符串的长度 - 2 * 最长公共子序列的长度就是答案

第二问统计方案数还是有点意思的
要注意当f[i-1][j] == f[i][j-1]的时候,方案可以同时从这两边转移过来

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define LL long long
using namespace std;
LL read() {
    LL k = 0, f = 1; char c = getchar();
    while(c < '0' || c > '9') {
        if(c == '-') f = -1;
        c = getchar();
    }
    while(c >= '0' && c <= '9') {
        k = k * 10 + c - 48; c = getchar();
    }
    return k * f;
}
LL tot = 0, f[50][50], cnt[50][50];
void solve() {
    memset(f, 0, sizeof(f)), memset(cnt, 0, sizeof(cnt));
    string s1, s2;
    getline(cin, s1); getline(cin, s2);
    int len1 = s1.size(), len2 = s2.size();
    for(int i = 0; i <= 40; ++i) cnt[i][0] = cnt[0][i] = 1;

    for(int i = 1; i <= len1; ++i)
        for(int j = 1; j <= len2; ++j) {
            if(f[i][j-1] > f[i-1][j]) cnt[i][j] = cnt[i][j-1];
            else if(f[i][j-1] < f[i-1][j]) cnt[i][j] = cnt[i-1][j];
            else cnt[i][j] = cnt[i-1][j] + cnt[i][j-1];

            f[i][j] = max(f[i][j-1], f[i-1][j]);
            if(s1[i-1] == s2[j-1]) {
                f[i][j] = f[i-1][j-1] + 1;
                cnt[i][j] = cnt[i-1][j-1];
            }
        }
    printf("Case #%lld: %lld %lld\n", tot, len1 + len2 - f[len1][len2], cnt[len1][len2]);
}
int main() {
    int k; scanf("%d\n", &k);
    while(k--) {
        ++tot;
        solve();
    }
    return 0;
}
12-30 19:52