LuoGu1439 LCS模板

 

作为特别特别经典的一类序列DP,相信大家都应该了解LCS吧!

那么最基本的n方做法就只简述一下:

设f[i][j]表示第一个序列匹配到了第i位,第二个匹配到了第j位;

转移

f[i][j]=max (f[i-1][j], f[i][j-1]);
if (a[i]==b[j]) f[i][j]=max (f[i][j], f[i-1][j-1]+1);

然后 n方此处不够优秀

对于两个都是1-n的一个排列的求LCS的问题(LuoGu P1439 模板)是可以nlogn解决的

考虑怎么优化 。

实际上我们可以发现,如果存在一组公共子序列,那么这就意味着他们在原序列中,对应位置的 相对大小 也是一定的(因为都是1-n)。

所以我们把其中一个序列的每一个值对应上其位置,另一个序列对应的转换,这样就只要求LIS就行了

例如 3 2 1 4 5 和 1 2 3 4 5:

把第一个先对应上其位置(用a数组),

a[3]=1, a[2]=2, a[1]=3, a[4]=4, a[5]=5

另外一个再对应一下,则得到3 2 1 4 5

这样再把1 2 3 4 5 和 3 2 1 4 5 求LIS 即 2 4 5,对应到原序列分别为 2 4 5就是他们的LCS。

这样问题就解决了。

Update:

SP33TRIP

题意:LCS方案输出。

思路:求出LCS长度后,预处理好前i个子母中,字母j出现的最后位置。

然后DFS,依次枚举每一位填什么字母,注意好条件的限制就可以了。

void dfs (int x,int y,int num,string ss) {
    if (num==0) {ans.insert(ss);return;}
    for (RG int i=1;i<=26;++i) {
        if (la[x][i]>=num&&lb[y][i]>=num&&f[la[x][i]][lb[y][i]]==num) 
            dfs(la[x][i]-1,lb[y][i]-1,num-1,(char)(i+'a'-1)+ss);
    }
}
原文地址:https://www.cnblogs.com/Bhllx/p/9806864.html