题目

题目大意

给你两个字符串AAA和BBB,可以修改AAA中的一个字符,求修改后最长的AAA的前缀,使它是BBB的子串。


思考历程

看到这道题之后,第一眼想到的就是后缀自动机!
BBB的子串,意味着可以把BBB建立一个后缀自动机,然后在上面跑……
刚开始的想法是将AAA在上面跑,并且试着修改后面一个字符,看看剩下的可以跑多长……
于是问题就转化成求这样的一个东西:问AAA的某个后缀从后缀自动机上的某个节点开始最多能跑多远。
我试着将这个东西预处理出来……可是没有成功……
交了个错误的程序上去,居然还有点分。


水法

这题不得不开“水法”这一栏目。
题目的数据真是太水了,各种暴力都能过。
最简单的暴力:枚举子串的左端点,然后暴力匹配,遇见的第一个不同就用掉修改机会,求出匹配的最大长度。
还有一种O(n)O(n)O(n)的正确性显然错误的DP……
跑得都比正解快……

正解

有个exkmp的方法,虽然说时间可能会有点玄学,但既然是郑姐讲的方法,就把它归为“正解”这一栏吧……
求出AAA的nextnextnext,以AAA为模式串求出BBB的extendextendextend。
枚举子串的开头iii,则后面相同的子串长度为extendiextend_iextendi​。
后面那个位置用修改操作,所以要从Aextendi+2A_{extend_i+2}Aextendi​+2​和Bi+extendi+1B_{i+extend_i+1}Bi+extendi​+1​开始继续匹配。
接下来取min⁡(nextextendi+2,extendi+extendi+1)\min(next_{extend_i+2},extend_{i+extend_i+1})min(nextextendi​+2​,extendi+extendi​+1​)。后面这个长度的串一定是相同的,因为前者等于AAA前面一段,后者也等于AAA前面一段,其中的最小值就是它们相等的长度。
然而这可能不是极限,所以后面的,就暴力判断吧……
时间应该比较优秀,虽然说那一部分暴力判断有点玄学……

然后是题解中的LCPLCPLCP做法。
先枚举子串的左端点iii,求LCP(Bi..m,A)LCP(B_{i..m},A)LCP(Bi..m​,A),设为xxx。x+1x+1x+1位可以用修改机会,然后求LCP(Ax+2..n,Bi+x+1..m)LCP(A_{x+2..n},B_{i+x+1..m})LCP(Ax+2..n​,Bi+x+1..m​),就是后面能继续延伸的长度。
当然,记得判断一下到达边界的情况。
至于求LCPLCPLCP,最典型的做法是用后缀数组,将AAA和BBB并在一起,中间用特殊字符隔开,然后求后缀数组和heightheightheight数组,然后用数据结构维护区间heightheightheight最小值。
还有一种做法是用后缀自动机。考虑利用failfailfail指针,如果跳两个节点在failfailfail树上的LCALCALCA,它的lenlenlen就是它们的最长公共后缀。要求最长公共前缀,就把字符串倒过来建后缀自动机就行了……(failfailfail树实际上是逆序字符串的后缀树)这是两个字符串,所以要建广义后缀自动机。

最后是许多人使用的二分和hashhashhash做法。
首先二分答案kkk,将BBB串中长度为kkk的子串存入hashhashhash表。
然后26n26n26n来枚举修改的方案,每次修改后再hashhashhash表中查询。


代码

后缀自动机的做法……

using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cassert>
#define N 50010
int n,m;
char a[N],b[N];
struct Node{Node *c[26],*fail;int len;
} d[N*4];
int cnt;
Node *S,*last;
inline void insert(int ch){if (last->c[ch] && last->c[ch]->len==last->len+1){last=last->c[ch];return;}Node *nw=&d[++cnt],*p;nw->len=last->len+1;for (p=last;p && !p->c[ch];p=p->fail)p->c[ch]=nw;if (!p)nw->fail=S;else{Node *q=p->c[ch];if (p->len+1==q->len)nw->fail=q;else{Node *clone=&d[++cnt];memcpy(clone,q,sizeof(Node));clone->len=p->len+1;for (;p && p->c[ch]==q;p=p->fail)p->c[ch]=clone;nw->fail=q->fail=clone;}}last=nw;
}
int sta[N],stb[N];
int fa[N*4][17],dep[N*4];
int get_dep(int x){if (dep[x])return dep[x];if (!fa[x][0])return dep[x]=1;return dep[x]=get_dep(fa[x][0])+1;
}
int LCP(int u,int v){if (dep[u]<dep[v])swap(u,v);for (int k=dep[u]-dep[v],i=0;k;k>>=1,++i)if (k&1)u=fa[u][i];if (u==v)return d[u].len;for (int i=16;i>=0;--i)if (fa[u][i]!=fa[v][i])u=fa[u][i],v=fa[v][i];return d[fa[u][0]].len;
}
int main(){scanf("%s%s",a+1,b+1);n=strlen(a+1),m=strlen(b+1);n=min(n,m);last=S=&d[++cnt];for (int i=m;i>=1;--i){insert(b[i]-'a');stb[i]=last-d;}last=S;for (int i=n;i>=1;--i){insert(a[i]-'a');sta[i]=last-d;}fa[1][0]=0;for (int i=2;i<=cnt;++i)fa[i][0]=d[i].fail-d;for (int i=1;i<=cnt;++i)get_dep(i);for (int i=1;i<=16;++i)for (int j=1;j<=cnt;++j)fa[j][i]=fa[fa[j][i-1]][i-1];int ans=0;for (int i=1;i<=m;++i){int lcp=LCP(stb[i],sta[1]);if (lcp==n || lcp==n-1){printf("%d\n",n);return 0;}ans=max(ans,lcp+(i+lcp<=m?1:0)+(i+lcp+1<=m?LCP(stb[i+lcp+1],sta[1+lcp+1]):0));}printf("%d\n",ans);return 0;
}

总结

这题应该算是一道套路题吧……
所以看题的时候,不要试着死磕一个地方,要多方面地去考虑……
比如,枚举左端点右端点什么的……

[JZOJ3337] 【NOI2013模拟】wyl8899的TLE相关推荐

  1. jzoj3337-[NOI2013模拟]wyl8899的TLE【字符串hash,二分】

    正题 题目大意 两个字符串A,BA,BA,B.可以修改AAA中的一个字符使得AAA中的1∼k1\sim k1∼k是BBB的子串,求kkk的最大值. 解题思路 先将AAA和BBB字符串hashhashh ...

  2. 【NOI2013模拟】棋盘游戏

    Description 有一个N*M的棋盘,初始每个格子都是白色的. 行操作是指选定某一行,将这行所有格子的颜色取反(黑白互换). 列操作是指选定某一列,将这列所有格子的颜色取反. XX进行了R次行操 ...

  3. jzoj3339-[NOI2013模拟]wyl8899和法法塔的游戏【博弈论,暴力】

    正题 题目大意 有nnn堆石子,每次选择一个区间博弈,先手必须先取最右边的石子堆. 每次询问(r,a,b)(r,a,b)(r,a,b)表示在a∼ba\sim ba∼b中选择一个数lll.要求使用l∼r ...

  4. [JZOJ3347] 【NOI2013模拟】树的难题

    题目 题目大意 给你一棵树,每个节点有三种黑.白.灰三种颜色. 你要割掉一些边(每条边被割需要付出一定的代价),使得森林的每棵树满足: 没有黑点或至多一个白点. 思考历程 这题一看就知道是一个树形DP ...

  5. 3360. 【NOI2013模拟】苹果树

    题目描述 神犇家门口种了一棵苹果树.苹果树作为一棵树,当然是呈树状结构,每根树枝连接两个苹果,每个苹果都可以沿着一条由树枝构成的路径连到树根,而且这样的路径只存在一条.由于这棵苹果树是神犇种的,所以苹 ...

  6. 欢乐纪中某A组赛【2019.7.9】

    前言 我好菜我好菜我好菜我好菜我好菜 我好菜我好菜我好菜我好菜我好菜 我好菜我好菜我好菜我好菜我好菜 我好菜我好菜我好菜我好菜我好菜 我好菜我好菜我好菜我好菜我好菜 我好菜我好菜我好菜我好菜我好菜 心 ...

  7. AtCoder - 2153 An Ordinary Game list模拟 || 博弈

    http://abc048.contest.atcoder.jp/tasks/arc064_b?lang=en 在vj里面用list模拟水过去了,然后感觉vj不靠谱,上atcoder交,果然tle 我 ...

  8. ACM/ICPC 2018亚洲区预选赛北京赛站网络赛 80 Days(双向队列+尺取法)

    #1831 : 80 Days 时间限制:1000ms 单点时限:1000ms 内存限制:256MB 描述 80 Days is an interesting game based on Jules ...

  9. 学习手记(2019/7/05~2019/8/31)——快乐暑假

    文章目录 二分答案的作用 堆和区间 很糙ddp 线段树合并 网络流结论の1 树上莫队 对角线与GCD 区间与扫描线与方案数 欧拉欧拉*1 斯坦纳树 切比雪夫距离 二分匹配结论の1 min-max容斥 ...

  10. 欢乐纪中某A组赛【2019.7.12】

    前言 暴力写挂垫底了呀\huge \color{red}\texttt{暴力写挂}\small\color{white}\\\texttt{垫底了呀}暴力写挂垫底了呀 %%%ZZYrank1\text ...

最新文章

  1. golang存储密码
  2. 无法安装.msi文件
  3. 一年有几个月几个季度_胎教几个月开始 注意事项有哪些?
  4. VTK:网格之TableBasedClipDataSetWithPolyData2
  5. CSS中的IFC和BFC入门
  6. win7系统mysql连接不上数据库吗_Win7系统使用数据库时mysql频繁掉线无法连接的两种解决方法...
  7. “软件工程造价师”和“软件造价评估师”有什么区别?
  8. php存储富文本编辑器内容到数据库
  9. C#用NPOI控件把MySQL数据库中查询符合条件的数据导出到EXCEL
  10. 六大危害不容忽视 笔记本外接显示器杂谈
  11. matlab复信道化滤波器组,宽带数字信道化EDA设计
  12. 期货手续费怎么计算?
  13. U3D(Unity) 实现电路解密、通水管游戏
  14. 股票交易接口程序概述
  15. python qt是什么_初识Python与Qt
  16. python 滤波放大数组,python 双边滤波与高斯滤波
  17. 第三周总结(2022.10.31~2022.11.4)
  18. 电机学他励直流发电机matlab,华南理工电机学随堂练习答案完整版
  19. Linux -- 项目服务部署学习
  20. 机器人网络系统时延笔记(LAN+WLAN)

热门文章

  1. android popupwindow 消失动画,PopupWindow动画结束后dismiss崩溃解决
  2. 前端下载zip出现文件打不开
  3. 网络设备:中继器、集线器、网桥、交换机、路由器、网关的超全总结
  4. Ubantu查看json文件
  5. 720度全景图有什么优势?
  6. 前端流媒体:MSE入门
  7. 市面上的手机银行的简介
  8. 个人推荐一款并发测试工具
  9. 【大话设计模式】第0章 面向对象基础
  10. ppt如何替换其他mo ban_“华南师范大学”专属PPT模板来了!华南师大同学们的PPT我们承包了!...