-
- 题意:给出三个字符串的最长公共子序列长度 a = lcs(s1, s2), b = lcs(s2, s3), c = lcs(s1, s3),并规定这三个字符串长度为n,问是否能构造出满足上述条件的字符串s1、s2、s3。
- 解析:首先找出minL = min{a, b, c},说明这三个字符串的公共部分长度(是三个字符串共同的)至少为minL,那么用a、b、c分别减去minL后得到s1、s2、s3与某一个字符串还需构造的公共子序列长度a', b', c'。不难发现,至少有一个将会为0,我们可以举一个极端的例子:假设a'、b'均为0,若c' + minL > n说明肯定构造不出这三个字符串,因为此时s1/s3长度已经超过n,再推广到一般情况,可以得知a' + b' + c' + minL <= n时候才能构造出三个字符串(当只有一个为0时可以通过传递性进行理解,或者举例找规律) 。接下来是构造三个字符串方法:
- 首先初始化三个字符串的公共部分:minL长度的'a'(可为任意字符);
- 构造长度为a'的(s1、s2)、长度为b'的(s2、s3)、长度为c'的(s1、s3),依次往每个对子的字符串后累加其长度的相同字符;
- 为使得这三个字符串长度达到n,最后赋剩余长度的字符串不同的字符串(该串所有字符相同、避免产生更长的LCS)。
- 代码:
#include<iostream>
#include<cstdio>
using namespace std;
int a, b, c, n; //a、b、c代表s1、s2、s3的长度
int main()
{
cin >> a >> b >> c >> n;
int minL = min(a, min(b, c)); //s1、s2、s3的公共部分长度的下界
string s1(minL, 'a'), s2(minL, 'a'), s3(minL, 'a'); //构造s1、s2、s3的公共部分
a -= minL, b -= minL, c -= minL; //s1、s2、s3减去公共部分的长度
if(a + b + c + minL > n)
{
cout << "NO" << endl;
return 0;
}
for(int i = 1; i <= a; i++) //构造s1、s2
{
s1 += 'b';
s2 += 'b';
}
for(int i = 1; i <= b; i++) //构造s2、s3
{
s2 += 'c';
s3 += 'c';
}
for(int i = 1; i <= c; i++) //构造s1、s3
{
s1 += 'd';
s3 += 'd';
}
//补齐没有公共部分的字符
while(s1.length() < n) s1 += 'x';
while(s2.length() < n) s2 += 'y';
while(s3.length() < n) s3 += 'z';
cout << s1 << endl << s2 << endl << s3 << endl;
}