zoukankan      html  css  js  c++  java
  • UVa 10635

    看题

    题目


    在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;
    }
  • 相关阅读:
    CentOS查看CPU信息、位数、多核信息
    Linux常用命令大全
    chmod命令详细用法
    tar命令的详细解释
    yum和rpm命令详解
    LeetCode 241. Different Ways to Add Parentheses
    LeetCode 139. Word Break
    LeetCode 201. Bitwise AND of Numbers Range
    LeetCode 486. Predict the Winner
    LeetCode 17. Letter Combinations of a Phone Number
  • 原文地址:https://www.cnblogs.com/Siegfried-L/p/12668907.html
Copyright © 2011-2022 走看看