[BZOJ3620]似乎在梦中见过的样子
[BZOJ3620]似乎在梦中见过的样子
Tags:题解
题意
[NOI2014]动物园:对于字符串的每个位置\(i\),求出上长度\(\le\lfloor\frac{i}{2}\rfloor\)的\(Border\)数量
[BZOJ2620]似乎在梦中见过的样子:求满足存在\(Border\in[L,\lfloor\frac{i-1}{2}\rfloor]\)的位置\(i\)的数量
题解
求\(Border\)显然\(KMP\)
求解KMP的nxt数组过程是不能修改的!!!否则会对后面的求解产生影响
由于答案也是\(Border\),可以考虑类似\(KMP\)递推答案的\(pos\),记录\(pos[i]\)表示做到第i个位置时被算入答案(或恰好没有被算进答案)的位置
类似于\(KMP\)的过程,如果在\(i-1\)位置由于\(Border\)过长,位置\(k\)没有被算入答案,那么在\(i\)位置时位置\(k+1\)肯定也不能被算入答案。也就是说若当前\(Border\)过长,在\(i\)位置不是答案,那么在\(i+1....n\)位置也不可能是答案,于是直接跳\(nxt\)直到小于上界
复杂度用势能分析可得是\(\mathcal{O} (n)\),因为每次\(pos\)最多也只会往后移一位
当然这题要做\(n\)遍所以是\(\mathcal{O} (n^2)\),不晓得为什么跑得过去。。。
代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
using namespace std;
const int N=2e4;
int n,L,pos[N],nxt[N],ans;
char s[N];
void calc(int bs,int l)
{
for(int i=2;i<=l;i++)
{
int j=nxt[i-1],k=pos[i-1];
while(s[i+bs]!=s[j+1+bs]&&j) j=nxt[j];
nxt[i]=s[i+bs]==s[j+1+bs]?j+1:j;
while(k&&(s[i+bs]!=s[k+bs+1]||(k+1)*2>=i)) k=nxt[k];
k+=s[i+bs]==s[k+bs+1];pos[i]=k;
if(k>=L&&k*2<i) ans++;
}
}
int main()
{
scanf("%s%d",s+1,&L);
n=strlen(s+1);
for(int i=0;i<n;i++) calc(i,n-i);
cout<<ans<<endl;
}