题意:有两个字符串\(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. python3 TypeError: a bytes-like object is required, not 'str'

    在学习<Python web开发学习实录>时, 例11-1: # !/usr/bin/env python # coding=utf-8 import socket sock = sock ...

  2. Mysql版本java问题(com.mysql.cj.jdbc.Driver和com.mysql.jdbc.Driver)

    老版本com.mysql.jdbc.Driver已弃用 String url1 = "jabc:mysql://127.0.0.1:3306/test"; String url1 ...

  3. hdu5125 树状数组+dp

     hdu5125 他说的是n个人每个人都有两个气球a,b,气球各自都有相应的体积,现在让他们按照序号排列好来,对他们的a气球体积值计算最长上升子序列,对于这整个排列来说有m次机会让你将a气球替换成b气 ...

  4. web api HttpConfiguration

    //设置web api configuration public static void Register(HttpConfiguration config){ config.Services.Rep ...

  5. STL容器之set

    [1]set容器 一个集合(set)是一个容器,它其中所包含的元素的值是唯一的. [2]set容器方法 (1)set构造函数.插入函数.遍历过程 应用示例代码如下: #include <set& ...

  6. 设计模式之Proxy(代理)(转)

    理解并使用设计模式,能够培养我们良好的面向对象编程习惯,同时在实际应用中,可以如鱼得水,享受游刃有余的乐趣. Proxy是比较有用途的一种模式,而且变种较多,应用场合覆盖从小结构到整个系统的大结构,P ...

  7. Hive常用语句

    文章目录 1 显示分区 2 添加分区 3 删除分区 4 修改分区 5 添加列 6 修改列 7 修改表属性 8 表的重命名 显示分区 show partitions iteblog; 添加分区 ALTE ...

  8. tensorflow学习6

    g_w1 = tf.get_variable('g_w1', [z_dim, 3136], dtype=tf.float32, initializer=tf.truncated_normal_init ...

  9. nodejs之pm2自动重启服务

    pm2 start xxx #启动服务器 pm2 list #查看运行状态 pm2 logs #查看日志 pm2 restart xxx #重启应用 pm2 stop xxx #停止应用 监听修改,并 ...

  10. RSA 加密 解密 公钥 私钥 签名 加签 验签

    http://blog.csdn.net/21aspnet/article/details/7249401# http://www.ruanyifeng.com/blog/2013/06/rsa_al ...