• 2016集训测试赛(二十四)Problem B: Prz


    Description

    Solution

    这道题有两个关键点:

    • 如何找到以原串某一个位置为结尾的某个子序列的最晚出现位置
    • 如何找到原串中某个位置之前的所有数字的最晚出现位置中的最大值

    第一个关键点: 我们注意到每个数字在(M)(L)中最多只会出现一次. 以(M)为例, 我们从前往后逐位在原串中匹配, 数组f[i]表示(M)的前(i)位在原串中当前位置之前的最晚出现位置. 假设当前数字(x)(M)中出现位置为(p), 则

    [f[p] = egin{cases} f[p] = i, p == 1 \ f[p] = f[p - 1], p > 1 end{cases} ]

    至于其他长度的子序列, 其最晚出现位置并不会发生变化.

    第二个关键点: 我们记录每个数字的最晚出现位置即可.

    #include <cstdio>
    #include <cctype>
    #include <cstring>
    #include <algorithm>
    
    using namespace std;
    namespace Zeonfai
    {
        inline int getInt()
        {
            int a = 0, sgn = 1; char c;
            while(! isdigit(c = getchar())) if(c == '-') sgn *= -1;
            while(isdigit(c)) a = a * 10 + c - '0', c = getchar();
            return a * sgn;
        }
    }
    const int N = (int)1e6, M = (int)1e6;
    int main()
    {
    
    #ifndef ONLINE_JUDGE
    
        freopen("prz.in", "r", stdin);
        freopen("prz.out", "w", stdout);
    
    #endif
    
        using namespace Zeonfai;
        int len = getInt(), m = getInt();
        static int a[N + 1], s[N + 1], t[N + 1];
        for(int i = 1; i <= len; ++ i) a[i] = getInt();
        int lenS = getInt(), lenT = getInt();
        for(int i = 1; i <= lenS; ++ i) s[i] = getInt();
        for(int i = 1; i <= lenT; ++ i) t[i] = getInt();
        static int mp[N + 1]; memset(mp, -1, sizeof(mp));
        for(int i = 1; i <= lenS; ++ i) mp[s[i]] = i;
        static int rec[N + 1]; memset(rec, -1, sizeof(rec));
        static int f[N + 1], g[N + 1];
        for(int i = 1; i <= len; ++ i)
        {
            if(~ mp[a[i]])
            {
                if(mp[a[i]] == 1) rec[mp[a[i]]] = i;
                else rec[mp[a[i]]] = rec[mp[a[i]] - 1];
            }
            f[i] = rec[lenS];
        }
        memset(mp, -1, sizeof(mp));
        for(int i = 1; i <= lenT; ++ i) mp[t[i]] = i;
        memset(rec, -1, sizeof(rec));
        for(int i = len; i; -- i)
        {
            if(~ mp[a[i]])
            {
                if(mp[a[i]] == 1) rec[mp[a[i]]] = i;
                else rec[mp[a[i]]] = rec[mp[a[i]] - 1];
            }
            g[i] = rec[lenT];
        }
        memset(mp, -1, sizeof(mp));
        for(int i = len; i; -- i) if(mp[a[i]] == -1) mp[a[i]] = i;
        static int lst[N + 1]; lst[0] = -1;
        for(int i = 1; i <= len; ++ i) lst[i] = max(mp[a[i]], lst[i - 1]);
        int cnt = 0; static int ans[N];
        for(int i = 1; i <= len; ++ i) if(~ f[i] && ~ g[i] && a[i] == s[lenS] && lst[f[i] - 1] > g[i]) ans[cnt ++] = i;
        printf("%d
    ", cnt);
        for(int i = 0; i < cnt; ++ i) printf("%d ", ans[i]);
    }
    
    
  • 相关阅读:
    【足迹C++primer】32、定制操作_2
    pom文件miss artifact com.sun:tools:jar:1.5.0:system问题
    cents上运行wget报错:unable to resolve host address
    怎样定义函数模板
    06006_redis数据存储类型——String
    雷林鹏分享:C# 类型转换
    雷林鹏分享:C# 运算符
    雷林鹏分享:C# 循环
    雷林鹏分享:C# 判断
    雷林鹏分享:C# 方法
  • 原文地址:https://www.cnblogs.com/ZeonfaiHo/p/7519029.html
Copyright © 2020-2023  润新知