题解【洛谷P2516】[HAOI2010]最长公共子序列

题面

经典的 LCS 求方案数。

第一问很简单,直接 (O(n^2)) 求出序列 LCS 长度即可。

对于第二问,直接在转移的时候分类讨论一下,最后处理重复计算的情况就可以了。

注意这一题卡空间,需要开滚动数组优化空间。

#include <bits/stdc++.h>
#define DEBUG fprintf(stderr, "Passing [%s] line %d
", __FUNCTION__, __LINE__)
#define File(x) freopen(x".in","r",stdin); freopen(x".out","w",stdout)

using namespace std;

typedef long long LL;
typedef pair <LL, LL> PII;
typedef pair <LL, PII> PIII;

const LL INF = 0x3f3f3f3f, N = 5003, mod = 100000000;

LL n, m;
LL dp[2][N], g[2][N];
char s[N], t[N];

int main()
{
	//File("");
    scanf("%s", s + 1);
    scanf("%s", t + 1);
    n = strlen(s + 1) - 1, m = strlen(t + 1) - 1;
    g[1][0] = 1;
    for (LL i = 0; i <= m; i+=1) g[0][i] = 1;
    for (LL i = 1; i <= n; i+=1)
        for (LL j = 1; j <= m; j+=1)
        {
            dp[i & 1][j] = dp[i - 1 & 1][j], g[i & 1][j] = g[i - 1 & 1][j] % mod;
            if (dp[i & 1][j] == dp[i & 1][j - 1]) 
                (g[i & 1][j] += g[i & 1][j - 1]) %= mod;
            else if (dp[i & 1][j - 1] > dp[i & 1][j]) 
                dp[i & 1][j] = dp[i & 1][j - 1], g[i & 1][j] = g[i & 1][j - 1] % mod;
            if (s[i] == t[j])
            {
                if (dp[i - 1 & 1][j - 1] + 1 > dp[i & 1][j])
                    dp[i & 1][j] = dp[i - 1 & 1][j - 1] + 1, g[i & 1][j] = g[i - 1 & 1][j - 1] % mod;
                else if (dp[i - 1 & 1][j - 1] + 1 == dp[i & 1][j]) 
                    (g[i & 1][j] += g[i - 1 & 1][j - 1]) %= mod;
            }
            else if (dp[i & 1][j - 1] == dp[i - 1 & 1][j] && dp[i - 1 & 1][j] == dp[i - 1 & 1][j - 1]) 
                g[i & 1][j] -= g[i - 1 & 1][j - 1]; //重复转移的情况
        }
    printf("%lld
%lld
", dp[n & 1][m], (g[n & 1][m] % mod + mod) % mod);
	return 0;
}
原文地址:https://www.cnblogs.com/xsl19/p/12465302.html