【GDOI2014】beyond

21 篇文章 0 订阅
2 篇文章 0 订阅

Description

这里写图片描述
这里写图片描述

Input

第一行:包含一个整数N。

第二行:包含一个长度为N的字符串,字符串中只包含小写字母。

第三行:包含一个长度为N的字符串,字符串中只包含小写字母。

Output

输出答案只包含一个数字L,表示圆环最大可能有的格子数。

Sample Input

输入1:
5
abcdx
cdabz
输入2:
4
abcd
cdab

Sample Output

输出1:
4
输出2:
4

Data Constraint

对于20% 的数据,1 <= N <= 5,000

对于50% 的数据,1 <= N <= 600,000

对于100% 的数据,1 <= N <= 2,000,000

Solution

简化题意
如果答案为L,那么第一个字符串的前L个和第二个字符串的前L个循环同构,最大化L
显然可以枚举L,但不是最优
循环同构,那么假设第一个字符串被分成了两部分,把后面的部分拼到前面就和第二个字符串相同,那么可以枚举这个切断的位置i
合法就是s[i~l]=t[1~l-i+1],s[1~i-1]=t[l-i+1~l]
这是什么?
一个字符串的从某个位置开始于另一个字符串的前缀完全相同的最大长度
这就是EXKMP
对于两个字符串,互相求出extend,记为extenda[]和extendb[]
那么只需要extendb[extenda[i]]>i就满足条件了,画个图就可以理解

Code

#include<cstdio>
#include<algorithm>
#include<cstring>
#define N 2010000
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define cl(a) memset(a,0,sizeof(a))
using namespace std;
char s[N],t[N];
int next[N],n,extend[N],b[N];
struct node{
    int x,i;
}a[N];
void getextend()
{
    next[1]=n;
    int a=0,p=0;
    fo(i,2,n)
    {
        int j=next[i-a+1];
        if(i+j>p) for(j=max(0,p-i);i+j<=n && t[i+j]==t[j+1];j++);
        next[i]=j;
        if(i+j-1>p) a=i,p=i+j-1;
    }
    a=p=0;
    fo(i,1,n)
    {
        int j=next[i-a+1];
        if(i+j>p) for(j=max(0,p-i+1);i+j<=n && s[i+j]==t[j+1];j++);
        extend[i]=j;
        if(i+j-1>p) a=i,p=i+j-1;
    }
}
bool cnt(node x,node y){return x.x<y.x;}
int main()
{
    scanf("%d\n",&n);
    scanf("%s\n",s+1);
    scanf("%s\n",t+1);
    getextend();
    fo(i,1,n) b[i]=extend[i];
    swap(s,t);
    cl(extend);cl(next);
    getextend();
    int ans=0;
    fo(i,1,n)
    {

        int j=b[i];
        if(extend[j+1]>=i-1) ans=max(ans,i+j-1);

    }
    printf("%d",ans);
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值