【GDOI2014 DAY2】Beyond (扩展KMP)
【题目】


【题意】
Jodie和Aiden在做游戏。Jodie在一个长度为l字符串环上走路,他每离开一个就会记下格子当前字符。他让Aiden在他走了一圈后叫他停下来。Aiden决定耍一下Jodie,在他走了k步重复的格后才告诉他。Jodie离开的格子会随机变为一个字符。Jodie走了两次(起点可能不同),每次都走了n(即l+k)步。给出两个长度n的字符串,表示Jodie两次记录的字符串,问l最大可以是多少。 N<=100000
【分析】
做2次扩展KMP,枚举第二个串的第i位与第一个串对应。一开始容易走入的误区就是直接使用tend2[i]然后判断,但是我们其实不一定让i往后的串越长越好,因为可能前面匹配不了。但是可以确定的是前面的匹配长度已经固定了,即i-1,所以我们只要在第一个串中找到所有的tend1大于等于i-1的x,当x越大,匹配长度越大,所以我们找最大的x使得其tend1[x]大于等于i-1。 可以用二分+rmq或者线段树。 也可以一开始排个序,然后用树状数组动态加减,然后用二分查找。

再放一次扩展KMP部分的代码:(注意那个小于号和小于等于号那里!很重要!):
void get_nt(int x)
{
nt[1]=n;
int mx=0,id;
while(s[x][1+mx]==s[x][2+mx]&&mx<=n) mx++;
nt[2]=mx;id=2;
for(int i=3;i<=n;i++)
{
int now=nt[i-id+1];
if(i+now-1<mx) nt[i]=now;//-> i+now<=mx 注意不要写成i+now-1<=mx!!!
else
{
int j=mx-i+1;
if(j<0) j=0;
while(i+j<=n&&s[x][i+j]==s[x][1+j]) j++;
nt[i]=j;
id=i;mx=i+nt[i]-1;
}
}
} void get_td(int x,int y)
{
int mx=0,id;
while(s[x][1+mx]==s[y][1+mx]) mx++;
td[y][1]=mx;id=1;
for(int i=2;i<=n;i++)
{
int now=nt[i-id+1];
if(i+now-1<mx) td[y][i]=now;
else //i+now-1>=mx
{
int j=mx-i+1;
if(j<0) j=0;
while(i+j<=n&&s[x][1+j]==s[y][i+j]) j++;
td[y][i]=j;
id=i;mx=i+td[y][i]-1;
}
}
}
代码如下:
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define Maxn 2000010 int n;
char s[][Maxn];
int nt[Maxn],td[][Maxn]; int c[Maxn];
struct node
{
int x,y;
}t[Maxn]; bool cmp(node x,node y) {return x.y<y.y;} int mymax(int x,int y) {return x>y?x:y;} void get_nt(int x)
{
nt[]=n;
int mx=,id;
while(s[x][+mx]==s[x][+mx]&&mx<=n) mx++;
nt[]=mx;id=;
for(int i=;i<=n;i++)
{
// mx=id+nt[id]-1;
int now=nt[i-id+];
if(i+now-<mx) nt[i]=now;//-> i+now<=mx 注意不要写成i+now-1<=mx!!!
else
{
int j=mx-i+;
if(j<) j=;
while(i+j<=n&&s[x][i+j]==s[x][+j]) j++;
nt[i]=j;
id=i;mx=i+nt[i]-;
}
}
} void get_td(int x,int y)
{
int mx=,id;
while(s[x][+mx]==s[y][+mx]) mx++;
td[y][]=mx;id=;
for(int i=;i<=n;i++)
{
int now=nt[i-id+];
if(i+now-<mx) td[y][i]=now;
else //i+now-1>=mx
{
int j=mx-i+;
if(j<) j=;
while(i+j<=n&&s[x][+j]==s[y][i+j]) j++;
td[y][i]=j;
id=i;mx=i+td[y][i]-;
}
}
} void add(int x,int y)
{
for(int i=x;i<=n;i+=i&(-i))
c[i]+=y;
} int get_sum(int x)
{
int ans=;
for(int i=x;i>=;i-=i&(-i))
ans+=c[i];
return ans;
} int ffind(int r)
{
int l=;
while(l<r)
{
int mid=(l+r)>>;
if(get_sum(r)-get_sum(mid)>) l=mid+;
else r=mid;
}
if(get_sum(l)==) return ;
return l;
} int main()
{
scanf("%d",&n);
scanf("%s%s",s[]+,s[]+);
get_nt();get_td(,); get_nt();get_td(,); memset(c,,sizeof(c));
for(int i=;i<=n;i++)
{
t[i].x=i;
t[i].y=td[][i];
add(i,);
}
sort(t+,t++n,cmp); int now=,ans=;
for(int i=;i<=n;i++)
{
while(t[now].y<i-&&now<=n)
{
add(t[now].x,-);
now++;
}
int x=ffind(td[][i]+);
if(x) ans=mymax(ans,x+i-);
}
printf("%d\n",ans);
return ;
}
[BEYOND]
2016-08-20 10:55:34
【GDOI2014 DAY2】Beyond (扩展KMP)的更多相关文章
- 扩展KMP算法
一 问题定义 给定母串S和子串T,定义n为母串S的长度,m为子串T的长度,suffix[i]为第i个字符开始的母串S的后缀子串,extend[i]为suffix[i]与字串T的最长公共前缀长度.求出所 ...
- 扩展KMP --- HDU 3613 Best Reward
Best Reward Problem's Link: http://acm.hdu.edu.cn/showproblem.php?pid=3613 Mean: 给你一个字符串,每个字符都有一个权 ...
- KMP和扩展KMP
文章网上太多这里提一下代码细节: KMP: scanf("%s\n",s); scanf("%s\n",t); int ls=strlen(s),lt=strl ...
- UVA5876 Writings on the Wall 扩展KMP
扩展KMP的简单题. #include<stdio.h> #include<string.h> #define maxn 51010 char s[maxn],t[maxn]; ...
- hdu4333 扩展KMP
慢慢研究可以发现,可以用扩展kmp来求.由于扩展kmp的next[]只有一部分,当前位子前面那部分和母串的后部分,所以可以将字符串复制接在后面一次. 先求如果next[]>0&& ...
- 扩展KMP
刘雅琼论文 http://wenku.baidu.com/view/8e9ebefb0242a8956bece4b3.html 论文讲的非常详细. 给定母串S,子串T,n=strlen(S),m=st ...
- HDU 3336 扩展kmp
题目大意: 找到字符串中所有和前缀字符串相同的子串的个数 对于这种前缀的问题,通常通过扩展kmp来解决 其实吧这是我第一次做扩展kmp的题目,原来确实看过这个概念,今天突然做到,所以这个扩展kmp的模 ...
- acdream1116 Gao the string!(扩展KMP)
今天是字符串填坑的一天,首先填的第一个坑是扩展KMP.总结一下KMP和扩展KMP的区别. 在这里s是主串,t是模式串. KMP可以求出的是以s[i]为结尾的串和 t前缀匹配的最长的长度.假如这个长度是 ...
- hdu 4333(扩展kmp)
题意:就是给你一个数字,然后把最后一个数字放到最前面去,经过几次变换后又回到原数字,问在这些数字中,比原数字小的,相等的,大的分别有多少个.比如341-->134-->413-->3 ...
随机推荐
- SQL语句修改表
-- 更改字段类型 默认值 alter table 表名 alter column 字段名 类型 ALTER TABLE 表名 add DEFAULT ('修改后的默认值') for 字段名 WITH ...
- C# 调用Java Webservice 加入SoapHeader 验证信息
C#调用java 编写的webservice时不会自动生成 soapheader 类接口的,需要改动Reference.cs. 在生成的代理类referende.cs中进行如下操作: 一.在声明pub ...
- ionic(一) build你的第一个android apk
1.ionic start myApp tabs >>创建一个app 2.cd myApp >>进入myApp文件 3.ionic platform add andro ...
- java 知识 链接
www.java2blog.com/2016/04/hashmap-in-java-with-examples.html HashMap全剖析 http://card.weibo.com/articl ...
- 01_JavaMail_01_邮件服务器简述
[收发邮件简单流程] 过程大致是: 发邮件时从客户端发邮件发送到邮件服务器,收邮件就是把邮件服务器的邮件下载到客户端. [邮件协议] * SMTP:(Simple Mail Transfer Prot ...
- UVA 11995 I Can Guess the Data Structure!(ADT)
I Can Guess the Data Structure! There is a bag-like data structure, supporting two operations: 1 x T ...
- docker中搭建gitlab
1, 下载镜像 docker pull sameersbn/gitlab:7.4.3 # 下载gitlab镜像 docker pull sameersbn/mysql:latest # 下载gitla ...
- Windows7 下安装 CentOS6.5
内容来自:http://blog.163.com/for_log/blog/static/2162830282013031031278/第一部分:安装前准备1. 准备两个fat32格式的分区,一个用于 ...
- html渐隐轮播
这是我之前用的时候从一个模板中下载下来用的,现在又用到了,我又重新找了一遍,为防止我下次用到忘记,特写下此文: 下载插件:jquery-2.1.4.min.js和slider.js 首页轮播页面首页i ...
- django之JavaScript的简单学习2
前言:ajax预备知识:json进阶 1.JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式.JSON是用字符串来表示Javascript对象: 请大家记住一 ...