牛客多校2021(四)C. LCS(构造、思维)

  • 题目:LCS

  • 题意:给出三个字符串的最长公共子序列长度 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时可以通过传递性进行理解,或者举例找规律) 。接下来是构造三个字符串方法:
    1. 首先初始化三个字符串的公共部分:minL长度的'a'(可为任意字符);
    2. 构造长度为a'的(s1、s2)、长度为b'的(s2、s3)、长度为c'的(s1、s3),依次往每个对子的字符串后累加其长度的相同字符;
    3. 为使得这三个字符串长度达到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;
}

posted @ 2021-07-29 10:24  ~K2MnO4  阅读(81)  评论(0)    收藏  举报