题目
在nxn的棋盘上,王子和公主玩游戏。棋盘上的正方形编号为1、2、3 ... n * n,如下所示:
Prince站在正方形1中,进行p跳跃,最后到达正方形n * n。他最多只能进入一个广场。因此,如果我们使用xp表示他输入的第p个平方,则x1,x2,... xp + 1都不同。注意,x1 = 1,xp + 1 = n * n。公主做类似的事情-站在方格1中,使q跳,最后到达方格n * n。我们使用y1,y2,... yq + 1表示序列,并且所有q + 1数均不同。
下面的图2显示了一个3x3的正方形,这是Prince的可能路线,而Princess的路线则不同。
王子按照以下顺序移动:1-> 7-> 5-> 4-> 8-> 3-> 9(黑色箭头),而公主按照以下顺序移动:1-> 4 -> 3-> 5-> 6-> 2-> 8-> 9(白色箭头)。
国王-他们的父亲刚来。“为什么要分开走?你是兄弟姐妹!” 国王说:“忽略一些跳跃,确保你们一直在一起。”
例如,如果王子忽略了他的第二,第三,第六跳,他将遵循以下路线:1-> 4-> 8->9。如果公主忽略了她的第三,第四,第五,第六跳,她将遵循相同的路线:1-> 4-> 8-> 9(常见路线如图3所示),因此满足了国王(如上所示)。国王想知道他们可以一起走的最长路线,你能告诉他吗?
输入值
输入的第一行包含一个整数t(1 <= t <= 10),后面是测试用例的数量。对于每种情况,第一行包含三个整数n,p,q(2 <= n <= 250,1 <= p,q <n * n)。第二行包含p + 1个不同的整数,范围为[1..n * n],即Prince的序列。第三行包含q + 1个不同的整数,范围为[1..n * n](公主的序列)。
输出量
对于每个测试案例,请打印案例编号和最长路径的长度。查看输出以获取样本输入以获取详细信息。
样本输入
1
3 6 7
1 7 5 4 8 3 9
1 4 3 5 6 2 8 9
样本输出
Case 1:4
一看是LCS, 于是写了上去,然后,就没有然后了...
显然,LCS它n^2这个效率肯定要TLE的...
那么考虑一个极妙的方法。
先看题目,答案要求一起走,那么也就是说在两个数组中,如果有 a[i]==b[j], 那么a[i]与b[j]就 有可能被选入最后答案。
那么,我们不妨标记出a走到 b到过的格子 或 b要到的格子 的时间。a 第 i 步走到了 n, b 第 j 步也走到了 n, 那么标记 b[j] 为 i。如果 b走到的格子, a 却没有走到,那么这个格子就不可能成为最后共同走的路径的一部分。
可以用map[i]存储第一个字符串a[]中 值为i 的 编号,用f[i]来记录a走到 ab都可以走到的格子 的时间。当读入b[i]时,如果map[b[i]]被更改了(即存储了a数组某个值的编号), 那么就说明b[i]与a数组中某个值(a[j])相等,根据上面的分析,b[i]就有可能被选入最后答案。让map[b[i]] 存储的编号,也就是a走到相同格子的 时间,赋值给f[++cnt]。再用二分求 f 数组LIS即可。
#include<cstdio> #include<cmath> #include<cstring> #include<algorithm> using namespace std; const int MAXN = 62500 + 3; int n, p, q, ans, map[MAXN], f[MAXN], low[MAXN]; int main(){ int T; scanf("%d",&T); for(int t=1;t<=T;t++){ memset(map, 0, sizeof(map)); memset(f, 0, sizeof(f)); scanf("%d%d%d",&n,&p,&q); int a, b; int cnt = 0; for(int i=1;i<=p+1;i++){ scanf("%d",&a);//这里可以直接用变量 map[a] = i; } for(int i=1;i<=q+1;i++){ scanf("%d",&b); if(map[b]){ f[++cnt] = map[b]; } } memset(low, 0x3f, sizeof(low)); low[1] = f[1]; ans = 1; for(int i=2;i<=cnt;i++){//二分求LIS if(f[i] > low[ans]){ low[++ans] = f[i]; }else{ int c = lower_bound(low+1, low+ans+1, f[i])-low; low[c] = f[i]; } } printf("Case %d: %d ",t,ans); } return 0; }