题意简述:给定字符串,num[i]定义为该字符串前i个字符构成的前缀的最长不相交可匹配前缀后缀的个数,求(num[i]+1)的乘积。
分析:很容易想到暴力跳nxt的方法,nxt跳到前缀长度一半时开始计数,但很可惜,时间复杂度为O(L^2),直接T飞。然后发现可以在求nxt的同时处理出step[i],表示从i跳到0所需要的次数,这样,只需要跳nxt直到第一次长度小于一半即可,然而时间复杂度依然没变。继续优化,发现主要是暴力跳nxt到长度一半这个过程太慢了,怎么优化呢?考虑倍增跳nxt。这样,就能将时间复杂度降为O(LlogL)了。
代码:
#include<stdio.h>
#include<string.h>
#define ll long long
const int N=1e6+10;
const ll p=1e9+7;
int n;
int nxt[N],lg[N],num[N],step[N];
int jump[N][20+2];
char s[N];
void get_nxt()
{
nxt[1]=0; step[1]=0; int i=1,j=0;
while (i<=n)
if ((j==0)||(s[i]==s[j]))
{
i++; j++;
nxt[i]=j; step[i]=step[j]+1;
}
else
j=nxt[j];
}
void get_lg()
{
for (int i=1;i<=N-5;i++) lg[i]=lg[i-1]+(1<<lg[i-1]==i);