首页 > 代码库 > Laoj P1659 noip模拟 - 道路规划(LCS的nlogn算法)

Laoj P1659 noip模拟 - 道路规划(LCS的nlogn算法)

试题描述
吉丽王国有n个城市,每个城市有两个“附属城市”,其中北部有n个城市,每个城市的编号都是1~n中的一个,且互不相同,南部的n个城市也是如此。
很遗憾,南北两边的城市之间还没有道路连接,这个南北交通运输带来了很大的麻烦。
国王吉丽设计规划了一种方案,决定先建n条道路,即编号相同的两个城市之间连上一条道路
技术分享
如图所示,这就是建完道路后的样子。
如果第i个城市和第j个城市的两条道路相交了,那么我们称这两个城市“平等互惠”
吉丽想找出一个城市集合,使得集合中的任意两个城市都“平等互惠”,吉丽还希望这个集合的大小尽可能大。
那最大是多少呢,请你回答他。
输入格式
第一行,一个整数,n。
第二行,n个整数,第i个数表示北部第i个城市的编号。
第三行,n个整数,第i个数表示南部第i个城市的编号。
输出格式
输出合法的城市集合的最大大小。
输入示例
5
1 4 5 2 3
3 4 2 1 5
输出示例
3
注释说明
【样例解释】
{1,3,4},{1,2,3}和{2,3,5}都是合法的方案,大小是3,显然是最大值。

【数据规模】
对于20%数据,n<=50;
对于50%数据,n<=500;
对于70%数据,n<=5000;
对于100%数据,n<=10^5。

 

【分析】

一开始的想法是先预处理然后求个lis之类的,也算靠了点边。

后来发现把第二个序列翻转后,取二者的lcs即可,数据范围10^5,明显留给nlogn的。

LCS的nlogn算法其实就是把LCS转成LIS,LIS的nlogn算法想必大家都会了。

怎么转化呢,举个栗子:

比如样例数据是1 4 5 2 3和3 4 2 1 5,第二个序列翻转后为5 1 2 4 3,用c[i]来表示第一个序列的第i个数在第二个序列中的位置。

此时c[5]={4, 2, 5, 3, 1},现在再对c数组求LIS就可以了。

注意,要求是集合中任意两个城市都为“平等互惠”,如果我们求出来LCS=1的话,这个集合就为空。 

 

【代码】

 1 #include <bits/stdc++.h>
 2 #define inf 0x7fffffff
 3 using namespace std;
 4 
 5 int n, a[100005], b[100005], c[100005], x, g[100005], ans, k, f[100005];
 6 
 7 void init() {
 8     cin >> n;
 9     for (int i=1;i<=n;++i)
10         scanf("%d", &a[i]);
11     for (int i=n;i>0;--i)  {
12         scanf("%d", &x);
13         b[x]=i;
14     }
15     for (int i=1;i<=n;++i)
16         c[i]=b[a[i]];
17 }
18 
19 void lis() {
20     for (int i=1;i<=n;++i)
21         g[i]=inf;
22     for (int i=1;i<=n;++i) {
23         k=lower_bound(g+1, g+n+1, c[i])-g;
24         g[k]=c[i];
25         f[i]=k;
26         ans=max(ans, f[i]);
27     }
28 }
29 
30 int main() {
31     init();
32     lis();
33     if (ans!=1)
34         cout << ans << endl;
35     else
36         cout << 0 << endl;
37 }

 

Laoj P1659 noip模拟 - 道路规划(LCS的nlogn算法)