关于解法这个讲的很清楚了,主要用了设关键点的巧妙思想。

主要想说的是一个刚学的方法:通过后缀自动机建立后缀树,再转成后缀数组。

后缀数组功能强大,但是最令人头疼的地方是模板太难背容易写错。用这个方法,只需要用上SAM的模板即可。

https://blog.csdn.net/lvzelong2014/article/details/79006541

反串后缀自动机的parent树就是原串的后缀树,一遍DFS即可求出后缀数组。

这样代码复杂度上可能稍简单些(在忘记SA模板的时候可以用),构建过程的复杂度也由$O(n\log n)$变为线性,但由于这个线性复杂度是非常满的,所以常常会比SA还要慢不少。注意SAM的数组最好开两倍,一倍是肯定不够的。

 #include<cstdio>
#include<cstring>
#include<algorithm>
#define mem(a) memset(a,0,sizeof(a))
#define LCP(x,y) SA.que(x,y)
#define LCS(x,y) SA1.que(n-y+1,n-x+1)
#define rep(i,l,r) for (int i=(l); i<=(r); i++)
typedef long long ll;
using namespace std; const int N=;
int n,T,f[N],g[N],log[N];
char s[N]; ll ans; struct Suffix{
int lst,cnt,np,tot,h[N],pos[N],x[N],b[N],mx[N];
int son[N][],fa[N],ch[N][],rk[N],sa[N],st[N][];
void init(){ lst=cnt=; tot=; mem(b); mem(ch); mem(fa); mem(son); } void ext(int c,int k){
int p=lst; lst=np=++cnt; pos[np]=k; b[np]=; mx[np]=mx[p]+;
while (p && !son[p][c]) son[p][c]=np,p=fa[p];
if (!p) fa[np]=;
else{
int q=son[p][c];
if (mx[q]==mx[p]+) fa[np]=q;
else{
int nq=++cnt; mx[nq]=mx[p]+; pos[nq]=pos[q];
while (p && son[p][c]==q) son[p][c]=nq,p=fa[p];
memcpy(son[nq],son[q],sizeof(son[nq]));
fa[nq]=fa[q]; fa[q]=fa[np]=nq;
}
}
} void build(){ rep(i,,cnt) ch[fa[i]][x[pos[i]+mx[fa[i]]]]=i; }
void dfs(int x){
if (b[x]) sa[rk[pos[x]]=++tot]=pos[x];
rep(i,,) if (ch[x][i]) dfs(ch[x][i]);
} void get(){
int k=;
rep(i,,n){
for (int j=sa[rk[i]-]; i+k<=n && j+k<=n && x[i+k]==x[j+k]; k++);
h[rk[i]]=k; if (k) k--;
}
} void rmq(){
rep(i,,n) st[i][]=h[i];
rep(i,,log[n])
rep(j,,n-(<<i)+) st[j][i]=min(st[j][i-],st[j+(<<(i-))][i-]);
} int ask(int l,int r){
l++; int t=log[r-l+];
return min(st[l][t],st[r-(<<t)+][t]);
} int que(int x,int y){ return ask(min(rk[x],rk[y]),max(rk[x],rk[y]));} void build_sa(char s[]){
for (int i=n; i; i--) ext(x[i]=s[i]-'a'+,i);
build(); dfs(); get(); rmq();
}
}SA,SA1; void solve(){
mem(f); mem(g);
for (int len=,x,y,l,r; *len<=n; len++)
for (int i=,j=len+; j<=n; i+=len,j+=len)
if (s[i]==s[j]){
x=LCS(i,j); y=LCP(i,j);
l=max(i,i-x+len); r=min(i+y,j);
if (r>l){
f[l+len]++; f[r+len]--;
g[l-len+]++; g[r-len+]--;
}
}
rep(i,,n) f[i]+=f[i-],g[i]+=g[i-];
rep(i,,n-) ans+=(ll)f[i]*g[i+];
} int main(){
freopen("bzoj4650.in","r",stdin);
freopen("bzoj4650.out","w",stdout);
log[]=; rep(i,,N) log[i]=log[i>>]+;
scanf("%d",&T);
while (T--){
SA.init(); SA1.init(); scanf("%s",s+); n=strlen(s+);
SA.build_sa(s); reverse(s+,s+n+);
SA1.build_sa(s); reverse(s+,s+n+);
ans=; solve(); printf("%lld\n",ans);
}
return ;
}

最新文章

  1. C#指定时间和当前时间的相差的月份、天数
  2. JavaScript 事件绑定及深入
  3. Android Retrofit网络请求Service,@Path、@Query、@QueryMap、@FieldMap (转)
  4. windows下php,redis配置
  5. AJAX原理及XMLHttpRequest对象分析
  6. 【mysql】一维数据TopN的趋势图
  7. 0x800a1391-Microsoft Jscript &quot;JSON未定义&quot;
  8. cf B. Making Sequences is Fun
  9. 如何获取jqGrid中选择的行的数据
  10. UITableViewStyleGrouped顶部留白问题
  11. (转载)HDU4565
  12. ASP.NET WebApi 简单记录
  13. TOGAF架构内容框架之构建块(Building Blocks)
  14. 鸟哥的linux私房菜学习-(二)VMware虚拟机及linux系统安装过程
  15. header头参数 确定该文件类型
  16. IOS 生成静态库文件(.framework)
  17. Perl的命令行参数和ARGV
  18. Linux----常用操作
  19. 10.110.20.16上的MQTT server
  20. flag -- 诡异的memcache标记

热门文章

  1. C&amp;C++——C与C++知识点
  2. 【BZOJ 4007】[JLOI2015]战争调度 DP+搜索+状压
  3. 解析Mybaits的insert方法返回数字-2147482646的原因
  4. LwIP - 打开keepalive功能
  5. namenode磁盘满引发recover edits文件报错
  6. html初探
  7. Apache服务器
  8. Linux2.6.32内核笔记(5)在应用程序中移植使用内核链表【转】
  9. StringUtils工具类的使用
  10. 【 Python 】函数的参数