【题目】

【题意】

  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. 简论数据库乐观悲观锁与并发编程中的CAS

    为了防止无良网站的爬虫抓取文章,特此标识,转载请注明文章出处.LaplaceDemon/ShiJiaqi. http://www.cnblogs.com/shijiaqi1066/p/5783205. ...

  2. (转)MyEclipse2014配置Tomcat开发JavaWeb程序JSP以及Servlet

    1.安装准备 1).下载安装MyEclipse2014,这已经是最新版本. 2).下载Tomcat 官网:http://tomcat.apache.org/ 我们选择8.0: http://tomca ...

  3. java中split以"."分割的问题

    今天开发中使用字符串分割函数split(),发现:输出的并不是想要的结果 或者直接报错都有可能 查询后才发现,需要转译 原来在java中函数split(".")必须是是split( ...

  4. 冒泡排序算法(C#实现)

    简单的冒泡排序算法,代码如下: ] = temp; hasExchangeAction =true; //发生过互换 } } if (!hasExchangeAction) //如果没有发生过互换,则 ...

  5. ios 系统参数用法

    qi前言:写一个宏来选择性地编译与运行为不同iOS所写的代码来支持多个版本的ios工程 #if __IPHONE_OS_VERSION_MIN_REQUIRED #import "xxxxx ...

  6. Objective-C 中的方法回掉

    Objective-C 中的方法回掉  Objective-C 中的方法调用 OC 类似C+,避免不了的内部的各种通信手段,函数调用,变量传递等,避免不了各种回掉等. 一.class直接调用 或者 o ...

  7. redis 在windows上运行

    参考自:https://github.com/ServiceStack/redis-windows 1.用vagrant 运行redis的最后版本 1.1在windows上安装vagrant http ...

  8. requirejs实践一 加载JavaScript文件

    首先,目录如下(根目录有一个index.html文件.有一个scripts文件夹): scripts文件夹有如下的文件 以下是index.html代码 <!DOCTYPE html> &l ...

  9. Codevs 3287 货车运输 2013年NOIP全国联赛提高组(带权LCA+并查集+最大生成树)

    3287 货车运输 2013年NOIP全国联赛提高组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 传送门 题目描述 Description A 国有 n 座 ...

  10. 用ContentProvider向系统增加联系人

    发现对系统的联系人进行操作的api很乱,感觉逻辑有点不清楚...... 主要用到这4个类: android.provider.ContactsContract.CommonDataKinds.Emai ...