【题目】

【题意】

  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)的更多相关文章

  1. 扩展KMP算法

    一 问题定义 给定母串S和子串T,定义n为母串S的长度,m为子串T的长度,suffix[i]为第i个字符开始的母串S的后缀子串,extend[i]为suffix[i]与字串T的最长公共前缀长度.求出所 ...

  2. 扩展KMP --- HDU 3613 Best Reward

    Best Reward Problem's Link:   http://acm.hdu.edu.cn/showproblem.php?pid=3613 Mean: 给你一个字符串,每个字符都有一个权 ...

  3. KMP和扩展KMP

    文章网上太多这里提一下代码细节: KMP: scanf("%s\n",s); scanf("%s\n",t); int ls=strlen(s),lt=strl ...

  4. UVA5876 Writings on the Wall 扩展KMP

    扩展KMP的简单题. #include<stdio.h> #include<string.h> #define maxn 51010 char s[maxn],t[maxn]; ...

  5. hdu4333 扩展KMP

    慢慢研究可以发现,可以用扩展kmp来求.由于扩展kmp的next[]只有一部分,当前位子前面那部分和母串的后部分,所以可以将字符串复制接在后面一次. 先求如果next[]>0&& ...

  6. 扩展KMP

    刘雅琼论文 http://wenku.baidu.com/view/8e9ebefb0242a8956bece4b3.html 论文讲的非常详细. 给定母串S,子串T,n=strlen(S),m=st ...

  7. HDU 3336 扩展kmp

    题目大意: 找到字符串中所有和前缀字符串相同的子串的个数 对于这种前缀的问题,通常通过扩展kmp来解决 其实吧这是我第一次做扩展kmp的题目,原来确实看过这个概念,今天突然做到,所以这个扩展kmp的模 ...

  8. acdream1116 Gao the string!(扩展KMP)

    今天是字符串填坑的一天,首先填的第一个坑是扩展KMP.总结一下KMP和扩展KMP的区别. 在这里s是主串,t是模式串. KMP可以求出的是以s[i]为结尾的串和 t前缀匹配的最长的长度.假如这个长度是 ...

  9. hdu 4333(扩展kmp)

    题意:就是给你一个数字,然后把最后一个数字放到最前面去,经过几次变换后又回到原数字,问在这些数字中,比原数字小的,相等的,大的分别有多少个.比如341-->134-->413-->3 ...

随机推荐

  1. ng1中 如何用双向绑定 实现单向绑定的初始时不显示双括号效果?

    ng1中 如何用双向绑定 实现单向绑定(ng-bind就可以不显示{{}})的初始时不显示双括号效果? AngularJS 实例 页面加载时防止应用闪烁: <div ng-app="& ...

  2. (转)Eclipse中junit框架的使用——单元测试

    [转]junit浅学笔记一 JUnit是一个回归测试框架(regression testing framework).Junit测试是程序员测试,即所谓白盒测试,因为程序员知道被测试的软件如何(How ...

  3. 万网免费主机wordpress快速建站教程-域名绑定及备案

    进入主机管理界面,点击管理 点击域名绑定,绑定域名项选择已有域名,选择已购买的域名,点击一键解析域名,点击添加,即可完成域名解析工作. 由于没有备案,备案状态显示为未备案,点击旁边的备案链接,跳转至阿 ...

  4. SQL Server 2008 TOP 新用途

    /***************创建测试表******************************/ IF NOT OBJECT_ID('[Demo_Top]') IS NULL DROP TAB ...

  5. SqlServer查找表中多余的重复记录

    1.查找表中多余的重复记录,重复记录是根据单个字段(peopleId)来判断 select * from people where peopleId in (select peopleId from ...

  6. .net的 async 和 await

    async 和 await 出现在C# 5.0之后,关系是两兄弟,Task是父辈,Thread是爷爷辈,这就是.net 多线程处理的东西,具体包括 创建线程,线程结果返回,线程中止,线程中的异常处理 ...

  7. CDN调度器HAProxy、Nginx、Varnish

    http://www.ttlsa.com/web/the-cdn-scheduler-nginx-haproxy-varnish/ CDN功能如下:1.将全网IP分为若干个IP段组,分组的依据通常是运 ...

  8. DLL中导出STL模板类的问题

    接上一篇. 上一篇的dll在编译过程中一直有一个警告warning C4251: ‘CLASS_TEST::m_structs’ : class ‘std::vector<_Ty>’ ne ...

  9. ActionBar只显示图标不显示文字

    问题:ActionBar菜单项android:showAsAction设置为android:showAsAction="always|withText"或者android:show ...

  10. Myeclipse配置mybatis的xml自动提示

    关于mapper的xml的文件的自动提示 mapper头: <?xml version="1.0" encoding="UTF-8"?><!D ...