BZOJ 3620 :似乎在梦中见过的样子

题目大意:给出一个长度为\(n\)的字符串和整数\(m\),求这个字符串有多少个子串满足ABA的形式,其中\(len(a) \geq m,len(b)\geq1\)

解析:

我们枚举子串的左端点,每次求出当前串的Fail数组,构造出KMP树,则对于每个右结点,我们要求的就是它的祖先结点中大于等于m的最小值,这个可以在构造Fail数组时顺便求出,总的时间复杂度为\(O(n^2)\)

代码:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector>

#define rep(i,x,y) for (int i=x;i<=y;i++)
#define dep(i,y,x) for (int i=y;i>=x;i--)
#define sz(x) (int)(x.size())

using namespace std;

typedef long long LL;

const int maxn=15000+23;

int n,m,size,L,R,cur,h[maxn],fail[maxn];

LL ans;

char a[maxn],s[maxn];

bool vis[maxn];


void get_fail()
{
 cur=0;fail[1]=0;
 rep(i,1,size-1)
 {
  while ((cur>0) && (a[i+1]!=a[cur+1])) cur=fail[cur];

  if (a[i+1]==a[cur+1]) cur++;
  fail[i+1]=cur;
  
  if (fail[i+1]<m) {h[i+1]=0;continue;} 
  if ((h[fail[i+1]]>=m)) h[i+1]=h[fail[i+1]];
  if ((h[fail[i+1]]==0)&&(fail[i+1]>=m)) h[i+1]=fail[i+1];
 }
}

int main()
{
 scanf("%s",s+1);
 n=strlen(s+1);

 scanf("%d",&m);
 
 if ((2*m+1)>n) {printf("%d\n",0);return 0;}

 L=2*m+1,R=n-2*m,ans=0;

 rep(i,1,R)
 {
  size=0;
  rep(j,i,n) a[++size]=s[j];

  get_fail();
  
  rep(j,L,size) if ((h[j]>0)&&((h[j]<<1)<j)) ans++;
 }

 printf("%lld\n",ans);

 return 0;
}



posted @ 2016-12-05 18:30  Krew  阅读(103)  评论(0编辑  收藏  举报