hunnu 11313 无重复元素序列的最长公共子序列转化成最长递增子序列 求法及证明

时间:2023-12-18 20:20:56

题目:http://acm.hunnu.edu.cn/online/?action=problem&type=show&id=11313

湖师大的比赛,见我的另一篇水题题解,这里要说的是我YY出来的C题,无重复元素序列的最长公共子序列。

用常规的做法会超时,于是我YY出来一个方法,记录第一组各个数字的位置,读取第二组,把第一组出现的相同数字的位置放入序列,没出现就不放。。。然后就转成LIS题目了。。。

具体用例子来说明下,比如两个序列

3 2 1 5 4

2 1 5 4 3

很明显,LCS是2 1 5 4,4个。

那么开个初始化为-1的数组rec存放第一个序列的位置,rec[i]为数字i出现的位置,-1表示没有出现(因为不能排除第二组元素在第一组没有出现的情况)。

在这里,3出现在第1个,于是rec[3]=1,以此类推,rec[]={3,2,1,5,4}。

读取第二个序列,将第一个序列出现的相同数字的位置放到数组lis里面,没出现就不放。

在这里rec[2]=2,rec[1]=3...所以lis[]={2,3,4,5,1}。

然后用n*logn求LIS,我直接用吉大的模版。。。

求出来是4,跟答案是一样的。

int main() {
// freopen("in", "r", stdin);
int rec[maxn], lis[maxn], n, tmp;
while (scanf("%d", &n) && n) {
int cnt = 0;
memset(rec, -1, sizeof(rec));
for (int i = 1; i <= n; i++) {
scanf("%d", &tmp);
rec[tmp] = i; //存放位置
}
for (int i = 1; i <= n; i++) {
scanf("%d", &tmp);
if (rec[tmp] != -1)
lis[cnt++] = rec[tmp]; //生成LIS
}
printf("%d\n", LIS(lis, cnt));
}
return 0;
}

证明,我也不是很懂,稍微讲讲吧。。。

构造LIS时,第一个序列出现的相同数字的位置放到数组lis里面,LIS里面的升序就变成是序列一的顺序,而求最长递增子序列原本就是按序列的顺序求的,所以求出来的顺序也是序列二的顺序。

而LIS取的是两个序列相同的元素,所以求出来的子序就是原来两个序列的LCS。

额,有点牵强。。。但这是我YY出来的,挺有成就感的。。。

其实想起来和LIS的另一种求法有点像,我以前老是用的方法:

就是把原序列复制一遍并排序,然后求LCS。。。这种吃力不讨好的求法。。。

That's all...