题目: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...