• AT2173 Shik and Copying String [思维题]


    Shik and Copying StringShik and Copying String

    题目描述请点击题目链接 .


    color{blue}{最初想法}

    先检查 无解情况 骗点分 .
    因为只有前面才会对后面造成影响, 所以 从后向前处理,
    分情况讨论

    1. Si=TiS_i=T_i, 无覆盖, 跳过 .
    2. Si=TiS_i=T_i, 有相应覆盖, 跳过 .
    3. Si=TiS_i=T_i, 无相应覆盖, 查找 (1,Min_L)(1, Min\_L)St=TiS_t=T_itt, 从 tt 向后覆盖, 若找不到, 无解. 若有其他覆盖, Ans++Ans ++ .
    4. SiTiS_i eq T_i, 有相应覆盖, 跳过 .
    5. SiTiS_i eq T_i, 无相应覆盖, 同 3.3.

    对影响的消除部分有细节 .
    栈不要开 1e6 !!!1e6 !!!, 会 MLEMLE .


    color{red}{正解部分}

    在这里插入图片描述

    大体思路跟上方差不多, 我怎么就没想到画二维图?!

    将过程图画出来, 发现字母之间覆盖关系马上就清楚了许多 .

    1. 字母覆盖折线不能相交.
    2. 覆盖折线要尽量 """贴" 着走 .

    考虑一个折线的产生对以后的折线有什么影响,
    看到图中红色箭头部分, 是 cc 产生的折线使得 aa 产生的折线不得不弯曲一次,

    这也可以看成是 cc 的折线拐点 传递 到了 aa, 使得 aa 产生第 22 个拐点 .
    假设又有新的折线加入, 可能又会接着 aa 的第二个拐点继续传, 进而产生第33个拐点, 同时 aa 的第一个拐点又会传递产生 新折线 的第 22 个拐点 , 以此类推 .

    当前 从后往前 遍历到了 ii, 且在 (1,)(1, 最后的覆盖起点) 中满足 St=TiS_t = T_i 的最大的编号为 tt,

    前方某个折线的 覆盖起点bgbg, 传递了 lenlen 次,

    则当且仅当 bglen+1ibg - len + 1 le i 的时候那个折线才会对现在造成影响,

    于是使用队列维护从后往前的操作中产生的折线, 每次弹出无用的折线, 剩下的折线对当前 ii 造成影响,
    设队列大小为 q_sizeq\_size, 则会多产生 q_sizeq\_size 个拐点 , 加上 当前折线 产生的 11 个拐点, 总共有 q_size+1q\_size + 1 个拐点 .

    ENDmathcal{END} .


    color{red}{实现部分}

    使用队列维护 .
    注意当 i=Min_li=Min\_l 时折线只有一个转折点 .

    #include<bits/stdc++.h>
    #define reg register
    
    const int maxn = 1000005;
    
    int N;
    
    char S[maxn];
    char T[maxn];
    
    int main(){
            scanf("%d", &N);
            scanf("%s%s", S+1, T+1);
            int flag = 1;
            for(reg int i = 1; i <= N; i ++)
                    if(S[i] != T[i]){ flag = 0; break ; }
            if(flag){ printf("0
    "); return 0; }
            int Min_l = N, Ans = 1;
            std::queue <int> Q;
            for(reg int i = N; i >= 1; i --){
                    Min_l = std::min(i, Min_l);
                    if(T[i] == T[i-1]) continue ;
                    while(Min_l && S[Min_l] != T[i]) Min_l --;
                    if(!Min_l){ printf("-1
    "); return 0; }
                    while(!Q.empty()){
                            if(Q.front()-Q.size()+1 > i) Q.pop();
                            else break ;
                    }
                    Q.push(Min_l);
                    if(Min_l != i) Ans = std::max(Ans, (int)Q.size() + 1);
            }
            printf("%d
    ", Ans);
            return 0;
    }
    
  • 相关阅读:
    c++ 用宏代替常用的函数
    爬取网易云音乐(包括歌词和评论)
    三种常见的单例模式
    函数式编程filter和map的区别
    四种常见排序算法(快速,冒泡,插入,选择排序)
    6.微信撤回消息的获取
    5.微信拜年短信自动回复
    4.深拷贝和浅拷贝
    3.迭代器以及迭代器的作用
    2.生成器计算出斐波那契数列
  • 原文地址:https://www.cnblogs.com/zbr162/p/11822527.html
Copyright © 2020-2023  润新知