题意:有两个字符串\(a,b\),下标从\(0\)开始。求数对\((i,j)\)满足\(a[i+1:j] + r(a[j:n]) + r(a[0:i+1]) = b\),其中\(r(s)\)表示字符串\(s\)的反串。若有多组解,输出其中\(i\)最大,然后\(j\)尽可能小的一组。

\(|a|,|b| \leq 10^6\)

首先考虑枚举\(i\)。那么,我们就要让\(a[i+1:j] + r(a[j:n]) = b[0:n-i-1]\)。因此,前面的\(a[i+1:j]\)必须是\(b\)的一个前缀。这个限制比较简单,求出最长公共前缀后,就可以转化为\(j \leq r\)的形式。

接下来,我们得满足\(r(a[j:n])\)是\(b[0:n-i-1]\)的一个后缀。并且,我们只要求出满足这个条件的最小的\(j\)就可以了。也就是求出\(a\)最长的后缀,它在翻转后也是\(b[0:n-i-1]\)的后缀。这个问题比较复杂,要进行化简。先解决翻转。记\(a_r\)为\(a\)的反串,那么,问题就成为求最长的\(a_r\)的前缀,它也是\(b[0:n-i-1]\)的后缀。开始于一个固定位置的前缀,结束于多个不同位置的后缀。仔细一想的话,这正是KMP中nex数组的定义。因此,我们把\(a_r\)和\(b\)连起来(分隔符还是要加的),求一遍nex数组就可以了。

顺便一提,最长公共前缀必须用EXKMP来求,不然会T。

时间复杂度\(O(n)\)。

#include <bits/stdc++.h>
using namespace std;
const int N = 1000010;
char a[N],b[N],s[N << 1];
int nex[N << 1],n,pre[N << 1],pw[N],ans1,ans2;
int main() {
cin.getline(a+1,N);
cin.getline(b+1,N);
if (strlen(a+1) != strlen(b+1)) {
puts("-1 -1");
return 0;
}
n = strlen(a+1);
for (int i = 1 ; i <= n ; ++ i)
s[i] = a[n - i + 1];
s[n+1] = 0;
for (int i = 1 ; i <= n ; ++ i)
s[i + n + 1] = b[i];
nex[0] = -1;
for (int i = 1, j = -1 ; i <= (n << 1) + 1 ; nex[i++] = ++ j)
while (j >= 0 && s[i] != s[j+1]) j = nex[j];
for (int i = 1 ; i <= n ; ++ i)
s[i] = b[i];
s[n+1] = 0;
for (int i = 1 ; i <= n ; ++ i)
s[i + n + 1] = a[i];
pre[1] = 2 * n + 1;
while (s[2 + pre[2]] == s[1 + pre[2]] && 2 + pre[2] <= 2 * n + 1)
++ pre[2];
int p = 2;
for (int i = 3 ; i <= 2 * n + 1 ; ++ i) {
if (pre[i - p + 1] < pre[p] + p - i)
pre[i] = pre[i - p + 1];
else {
int j = max(0,p + pre[p] - i);
while (s[i + j] == s[1 + j] && i + j <= 2 * n + 1)
++ j;
pre[i] = j;
p = i;
}
}
ans1 = ans2 = -1;
for (int i = 1 ; i <= n ; ++ i) {
int r = pre[i + n + 1] + i;
int l = nex[2 * n + 1 - (i-1)];
if (n - l + 1 <= r) ans1 = i - 2, ans2 = n - l;
if (a[i] != b[n-i+1]) break;
}
if (ans1 == -1) ans2 = -1;
printf("%d %d\n",ans1,ans2);
return 0;
}

小结:这道题难度其实不大,但推导过程较长,因此需要时刻保持思路清晰,心态平稳。

【做题】CF119D. String Transformation——KMP的更多相关文章

  1. [日记&做题记录]-Noip2016提高组复赛 倒数十天

    写这篇博客的时候有点激动 为了让自己不颓 还是写写日记 存存模板 Nov.8 2016 今天早上买了两个蛋挞 吃了一个 然后就做数论(前天晚上还是想放弃数论 但是昨天被数论虐了 woc noip模拟赛 ...

  2. SDOI2016 R1做题笔记

    SDOI2016 R1做题笔记 经过很久很久的时间,shzr终于做完了SDOI2016一轮的题目. 其实没想到竟然是2016年的题目先做完,因为14年的六个题很早就做了四个了,但是后两个有点开不动.. ...

  3. CCPC2018-湖南全国邀请赛 G String Transformation

    G.String Transformation 题目描述 Bobo has a string S = s1 s2...sn consists of letter a , b and c . He ca ...

  4. LCT做题笔记

    最近几天打算认真复习LCT,毕竟以前只会板子.正好也可以学点新的用法,这里就用来写做题笔记吧.这个分类比较混乱,主要看感觉,不一定对: 维护森林的LCT 就是最普通,最一般那种的LCT啦.这类题目往往 ...

  5. java做题笔记

    java做题笔记 1. 初始化过程是这样的: 1.首先,初始化父类中的静态成员变量和静态代码块,按照在程序中出现的顺序初始化: 2.然后,初始化子类中的静态成员变量和静态代码块,按照在程序中出现的顺序 ...

  6. NOIP做题练习(day2)

    A - Reign 题面 题解 最大子段和+\(DP\). 预处理两个数组: \(p[i]\)表示 \(i\) 之前的最大子段和. \(l[i]\)表示 \(i\) 之后的最大子段和. 最后直接输出即 ...

  7. SAM 做题笔记(各种技巧,持续更新,SA)

    SAM 感性瞎扯. 这里是 SAM 做题笔记. 本来是在一篇随笔里面,然后 Latex 太多加载不过来就分成了两篇. 标 * 的是推荐一做的题目. trick 是我总结的技巧. I. P3804 [模 ...

  8. UOJ 做题记录

    UOJ 做题记录 其实我这么弱> >根本不会做题呢> > #21. [UR #1]缩进优化 其实想想还是一道非常丝播的题目呢> > 直接对于每个缩进长度统计一遍就好 ...

  9. C语言程序设计做题笔记之C语言基础知识(下)

    C 语言是一种功能强大.简洁的计算机语言,通过它可以编写程序,指挥计算机完成指定的任务.我们可以利用C语言创建程序(即一组指令),并让计算机依指令行 事.并且C是相当灵活的,用于执行计算机程序能完成的 ...

随机推荐

  1. sitecore系统教程之媒体库

    您可以管理媒体库中的所有媒体项目,例如要嵌入网页的图像或供访问者下载的图像.媒体库包含所有媒体项目,例如图像,文档,视频和音频文件. 在媒体库中,您可以: 将所有媒体文件保存在一个位置,并将其组织在与 ...

  2. Linux 运维测试及第三应用及测试工具

    一 .第三方应用及测试工具链接地址 https://pan.baidu.com/s/1rLQ5NCZvxcy93YQ4fGFaBQ 1.linux LSI系列raid卡监测工具 1)使用参数详解链接: ...

  3. 【Hive学习之七】Hive 运行方式&权限管理

    环境 虚拟机:VMware 10 Linux版本:CentOS-6.5-x86_64 客户端:Xshell4 FTP:Xftp4 jdk8 hadoop-3.1.1 apache-hive-3.1.1 ...

  4. python 读csv格式的文件

    对于大多数的CSV 格式的数据读写问题,都可以使用csv 库 1. 直接读csv 以下是要操作的csv文件内容 import csv with open(r'C:\Temp\f.csv') as f: ...

  5. Hive中实现group concat功能(不用udf)

    在 Hive 中实现将一个字段的多条记录拼接成一个记录: hive> desc t; OK id string str string Time taken: 0.249 seconds hive ...

  6. linux下怎么删除名称带空格的文件

    linux下怎么删除名称带空格的文件-rm 'mysql bin.000005' 用引号把文件名括起来 某些情况下会出现名称带空格的文件, 如果想要删除的话,直接用rm mysql bin.00000 ...

  7. c# 类的知识

    在英语中类(class)是分类(classification)的根词.设计类的过程就是对信息进行分类,将相关信息放到有意义的实体中. 封装的目的: 封装就是定义类的重要原则.中心思想是:使用类的程序不 ...

  8. c# 制作弹窗

    1.右键选择添加,添加windows窗体 2.添加第几个窗体这就是Form几 3.具现化  窗口,然后调用       具现化窗口名+ShowDialog  就可以弹出新的窗口 这个功能需要使用,自己 ...

  9. 转:C# 使用资源文件 Resource.resx 的方法

    在写程序时, 可以把用到的 图标,图片,声音等外部资源,放在一个  .resx (资源文件)中. 这样的好处是不用考虑什么路径的问题.而且还对资源有保护的做用. 1.创建一个 ResourceFile ...

  10. Linux学习笔记之Linux 让进程在后台可靠运行的几种方法

    0x00 概述 我们经常会碰到这样的问题,用 telnet/ssh 登录了远程的 Linux 服务器,运行了一些耗时较长的任务, 结果却由于网络的不稳定导致任务中途失败.如何让命令提交后不受本地关闭终 ...