• AT2173


    一道乱搞的题...

    题意:给你两个字符串,每次操作步骤如下:从前向后扫描整个字符串,对于每一位都有两种选择,一种是保持原来的字符不变,另一种是把这一位上的字符变成和前一位一样(注意是操作后的前一位),问你至少需要多少次操作才能将第一个字符串变成第二个字符串,如果不可能输出-1

    题解:

    看到网上所有人都在说“画一画就好”,然而我这种蒟蒻根本不会画啊喂!!!

    因此这篇博客的目的在于...谈一谈怎么画...

    首先我们不难看到:最佳的方法一定是从后向前修改(因为如果从前向后修改,很有可能把要用的字符覆盖掉了,这样就无法成功覆盖了)

    接下来,我们维护一个单调递减的变量$posi$,用于记录上一个先前最早匹配的位置在哪

    可能这句话并不好理解,我们举个例子讲:

    比如原串是$acbaba$,而目标串是$acbacb$,那么合理的对应方式应当是这样的:

    可以看到,虽然4号位置上的$a$之前最近的就是自己上面的$a$,但是不能直接继承,因为5号位上的$c$已经把匹配位置放到2了,为了保证正确覆盖,必须用之前的$a$,这也就导致了前面的无法匹配,所以这是一个无解情况!

    那么我们回到有解的情况:

    如果有解的话,显然原串中的每一个点最后会覆盖到目标串上的一段区间(废话),那么我们取出这个区间的最左端点来研究即可。

    不难发现,每一个值在覆盖的时候一定是一种折线的形式!

    举个例子:

    这是一个例子的部分情况

     可以发现:为了覆盖上那三个$a$,我们应该用原来的$a$覆盖整个区间

    但是为了避免中间的位置被错误覆盖导致这之后的位置被覆盖,所以我们应该用中间的位置覆盖再去覆盖后面的位置!

    举个例子:

    $s="abcde",t="aaacc"$

    为了防止a开始覆盖后覆盖掉了c导致后面无法被覆盖,我们要先用c去覆盖

    所以针对a而言,它的覆盖过程更应该是一条折线!

    或者,应该是这样:

    每次向前拓展了一个部分,直到能覆盖上目标即可。

    因此,我们只需要求出这样的折线最多折了几次就是答案!

    怎么求?

    我们开一个队列,队列里储存这样的折线中需要折的每个位置(也即一个位置对应一次偏折),那么队列的大小即为偏折的次数

    然后每次将无用的位置弹出队列即可。

    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <cstdlib>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    #include <stack>
    using namespace std;
    char s[1000005],t[1000005];
    queue <int> Q;
    int n;
    bool check()
    {
        for(int i=1;i<=n;i++)if(s[i]!=t[i])return 0;
        return 1;
    }
    int main()
    {
        freopen("game.in","r",stdin);
        freopen("game.out","w",stdout);
        scanf("%d",&n);
        scanf("%s%s",s+1,t+1);
        if(check()){printf("0
    ");return 0;}
        int posi=n;
        int ans=0;
        for(int i=n;i>=1;i--)
        {
            if(t[i]==t[i-1])continue;
            posi=min(posi,i);
            while(posi&&t[i]!=s[posi])posi--;
            if(!posi){printf("-1
    ");return 0;}
            while(!Q.empty())
            {
                if((int)Q.front()-(int)Q.size()>=i)Q.pop();
                else break;
            }
            Q.push(posi);
            if(i!=posi)ans=max(ans,(int)Q.size());
        }
        printf("%d
    ",ans+1);
        return 0;
    }
  • 相关阅读:
    springcloud 项目源码 微服务 分布式 Activiti6 工作流 vue.js html 跨域 前后分离
    springcloud 项目源码 微服务 分布式 Activiti6 工作流 vue.js html 跨域 前后分离
    OA办公系统 Springboot Activiti6 工作流 集成代码生成器 vue.js 前后分离 跨域
    java企业官网源码 自适应响应式 freemarker 静态引擎 SSM 框架
    java OA办公系统源码 Springboot Activiti工作流 vue.js 前后分离 集成代码生成器
    springcloud 项目源码 微服务 分布式 Activiti6 工作流 vue.js html 跨域 前后分离
    java 视频播放 弹幕技术 视频弹幕 视频截图 springmvc mybatis SSM
    最后阶段总结
    第二阶段学习总结
    第一阶段学习总结
  • 原文地址:https://www.cnblogs.com/zhangleo/p/10853306.html
Copyright © 2020-2023  润新知