[BZOJ3620]似乎在梦中见过的样子(kmp)
2017-04-17 21:31
253 查看
题目描述
传送门题目大意:给出一个字符串,求有多少个子串满足是A+B+A的形式,其中|A|>=k,|B|>=1。
题解
做这道题之前就已经知道了资瓷O(n2)的kmp然后就对于字符串的每一个后缀求一次失配,然后建出fail树,一个点产生贡献的条件是它到根的路径上存在一个点离根的距离>=k,且2*长度<这个点
那么每一个点保存一下满足条件的最小的点,每一个点从父亲转移过来
狂卡一波常数…
不要直接把树建出来,直接从左到右枚举每一个点,这样父亲一定已经被更新过了
还有就是将乘除运算改成位运算,快好多
代码
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #include<cmath> using namespace std; #define N 15003 char s ; int n,k,ans; int T ,last ; void calc_T(int loc) { T[loc]=loc-1; for (int i=loc;i<n;++i) { int j=T[i]; while (j!=loc-1&&s[i]!=s[j]) j=T[j]; T[i+1]=++j; } } void solve(int loc) { calc_T(loc); memset(last,-1,sizeof(last)); for (int i=loc;i<=n;++i) { int fa=T[i]; if (fa!=-1&&last[fa]!=-1) last[i]=last[fa]; else {if (i-loc>=k) last[i]=i;} if (last[i]!=-1&&loc+((last[i]-loc)<<1)<i) ++ans; } } int main() { scanf("%s",s);scanf("%d",&k); n=strlen(s);int limit=n-k-k; for (int i=0;i<limit;++i) solve(i); printf("%d\n",ans); }
相关文章推荐
- BZOJ.3620.似乎在梦中见过的样子(KMP)
- BZOJ 3620: 似乎在梦中见过的样子(kmp)
- BZOJ 3620: 似乎在梦中见过的样子 [KMP 暴力]
- 【BZOJ3620】似乎在梦中见过的样子【KMP】【暴力】
- BZOJ3620 似乎在梦中见过的样子(kmp)
- BZOJ 3620 似乎在梦中见过的样子 KMP+暴力
- bzoj 3620 似乎在梦中见过的样子(KMP)
- BZOJ_3620_似乎在梦中见过的样子_KMP
- 【BZOJ3620】似乎在梦中见过的样子 KMP
- BZOJ[3620]似乎在梦中见过的样子 KMP
- BZOJ3620: 似乎在梦中见过的样子 KMP
- bzoj 3620: 似乎在梦中见过的样子 (KMP)
- BZOJ 3620: 似乎在梦中见过的样子 KMP
- 【bzoj3620】似乎在梦中见过的样子 KMP
- [BZOJ 3620] 似乎在梦中见过的样子 【KMP】
- 【bzoj3620】【似乎在梦中见过的样子】【kmp】
- 【bzoj3620】 似乎在梦中见过的样子 KMP
- 【BZOJ 3620】 3620: 似乎在梦中见过的样子 (KMP)
- 【BZOJ3620】似乎在梦中见过的样子 KMP
- BZOJ 3620 似乎在梦中见过的样子