UVa 10635 - Prince and Princess

看题

题目


在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\n",t,ans);
    }
    return 0;
}

 

posted @ 2020-04-09 18:57  Sky_Sparks  阅读(272)  评论(0编辑  收藏  举报