UOJ #219 BZOJ 4650 luogu P1117 [NOI2016]优秀的拆分 (后缀数组、ST表)

连NOI Day1T1都不会做。。。看了题解都写不出来还要抄Claris的代码。。

题目链接: (luogu)https://www.luogu.org/problemnew/show/P1117

(bzoj)https://www.lydsy.com/JudgeOnline/problem.php?id=4650

(uoj)http://uoj.ac/problem/219

题解:

\(f[i]\)表示以\(i\)结束的\(AA\)型子串个数,\(g[i]\)表示以\(i\)开始的\(AA\)型子串个数

怎么求\(f,g\)?

打破思维定势,谁说必须要一个一个求呢

分长度来求

枚举长度\(L\), 处理所有长度为\(2L\)的\(AA\)型子串对\(f\)和\(g\)的贡献

如果每隔\(L\)的长度放一个打点计时器,呸,关键点

那么任何\(AA\)型子串都会经过两个相邻关键点

首先肯定要满足这两个关键位置上的字符一样

在这个基础上求出往前往后最多多少个一样的

这个就转化成了LCP和LCS问题,并且两个相邻关键点对\(f,g\)数组的影响是区间+1,使用差分前缀和解决

然后推一推就行了,注意+1-1不要推错

时间复杂度为调和级数,\(O(n\log n)\)

代码

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define llong long long
using namespace std;const int N = 1<<15;
const int LGN = 15;
const int S = 26;
int log2[N+3];
struct SparseTable
{int n;int str[N+3];int rk[N+3];int tmp[N+3];int height[N+3];int h[N+3];int sa[N+3];int wb[N+3];int mini[N+3][LGN+3];void get_sa(){int *x = rk,*y = tmp;for(int i=0; i<=S; i++) wb[i] = 0;for(int i=1; i<=n; i++) wb[x[i]=str[i]]++;for(int i=1; i<=S; i++) wb[i] += wb[i-1];for(int i=n; i>=1; i--) sa[wb[x[i]]--] = i;int s = S,p = 0;for(int j=1; p<n; j<<=1){p = 0;for(int i=n-j+1; i<=n; i++) y[++p] = i;for(int i=1; i<=n; i++) if(sa[i]>j) y[++p] = sa[i]-j;for(int i=1; i<=s; i++) wb[i] = 0;for(int i=1; i<=n; i++) wb[x[y[i]]]++;for(int i=1; i<=s; i++) wb[i] += wb[i-1];for(int i=n; i>=1; i--) sa[wb[x[y[i]]]--] = y[i];swap(x,y);p = 1; x[sa[1]] = 1;for(int i=2; i<=n; i++) x[sa[i]] = (y[sa[i]]==y[sa[i-1]] && y[sa[i]+j]==y[sa[i-1]+j]) ? p : ++p;s = p;}for(int i=1; i<=n; i++) rk[sa[i]] = i;for(int i=1; i<=n; i++){h[i] = h[i-1]==0 ? 0 : h[i-1]-1;while(i+h[i]<=n && sa[rk[i-1]]+h[i]<=n && str[i+h[i]]==str[sa[rk[i]-1]+h[i]]){h[i]++;}}for(int i=1; i<=n; i++) height[i] = h[sa[i]];for(int i=1; i<=n; i++) mini[i][0] = height[i];for(int j=1; j<=LGN; j++){for(int i=1; i+(1<<j)-1<=n; i++){mini[i][j] = min(mini[i][j-1],mini[i+(1<<j-1)][j-1]);}}}int querymin(int lb,int rb){int g = log2[rb-lb+1];return min(mini[lb][g],mini[rb-(1<<g)+1][g]);}int LCP(int x,int y){if(x==y) return n-x+1;if(rk[x]>rk[y]) swap(x,y);return querymin(rk[x]+1,rk[y]);}void clear(){for(int i=1; i<=n; i++) str[i] = rk[i] = tmp[i] = height[i] = h[i] = sa[i] = wb[i] = 0;for(int i=1; i<=n; i++){for(int j=0; j<=LGN; j++){mini[i][j] = 0;}}}
} s1,s2;
llong f[N+3];
llong g[N+3];
char a[N+3];
int n;int LCP(int x,int y) {return s1.LCP(x,y);}
int LCS(int x,int y) {return s2.LCP(n+1-x,n+1-y);}void preprocess()
{log2[1] = 0; for(int i=2; i<=N; i++) log2[i] = log2[i>>1]+1;
}void clear()
{s1.clear(); s2.clear();for(int i=0; i<=n+1; i++) a[i] = 0,f[i] = g[i] = 0ll;
}int main()
{preprocess();int T; scanf("%d",&T);while(T--){scanf("%s",a+1); n = strlen(a+1); for(int i=1; i<=n; i++) a[i]-=96;for(int i=1; i<=n; i++) s1.str[i] = a[i]; s1.n = n;s1.get_sa();for(int i=1; i<=n; i++) s2.str[i] = a[n+1-i]; s2.n = n;s2.get_sa();for(int i=1; i+i<=n; i++){for(int j=i+i; j<=n; j+=i){if(a[j]==a[j-i]){int lb = j-LCS(j,j-i)+1,rb = j+LCP(j,j-i)-1;lb = max(lb+i-1,j); rb = min(rb,j+i-1);if(lb<=rb){f[lb]++; f[rb+1]--;g[lb-i-i+1]++; g[rb+1-i-i+1]--;}}}}for(int i=1; i<=n; i++) f[i] += f[i-1],g[i] += g[i-1];llong ans = 0ll;for(int i=1; i<n; i++){llong tmp = f[i]*g[i+1];ans += tmp;}printf("%lld\n",ans);clear();}return 0;
}

发表于 2019-06-16 20:28 suncongbo 阅读(...) 评论(...) 编辑 收藏

刷新评论刷新页面返回顶部

UOJ #219 BZOJ 4650 luogu P1117 [NOI2016]优秀的拆分 (后缀数组、ST表)相关推荐

  1. BZOJ.4650.[NOI2016]优秀的拆分(后缀数组 思路)

    BZOJ 洛谷 令\(st[i]\)表示以\(i\)为开头有多少个\(AA\)这样的子串,\(ed[i]\)表示以\(i\)结尾有多少个\(AA\)这样的子串.那么\(Ans=\sum_{i=1}^{ ...

  2. NOI 2016 优秀的拆分 (后缀数组+差分)

    题目大意:给你一个字符串,求所有子串的所有优秀拆分总和,优秀的拆分被定义为一个字符串可以被拆分成4个子串,形如$AABB$,其中$AA$相同,$BB$相同,$AB$也可以相同 作为一道国赛题,95分竟 ...

  3. P1117 [NOI2016]优秀的拆分

    $ \color{#0066ff}{ 题目描述 }$ 如果一个字符串可以被拆分为\(AABB\)的形式,其中 A和 B是任意非空字符串,则我们称该字符串的这种拆分是优秀的. 例如,对于字符串\(aab ...

  4. UOJ #395 BZOJ 5417 Luogu P4770 [NOI2018]你的名字 (后缀自动机、线段树合并)

    NOI2019考前做NOI2018题.. 题目链接: (bzoj) https://www.lydsy.com/JudgeOnline/problem.php?id=5417 (luogu) http ...

  5. UOJ #131 BZOJ 4199 luogu P2178【NOI2015】品酒大会 (后缀自动机、树形DP)

    UOJ #131 BZOJ 4199 luogu P2178[NOI2015]品酒大会 (后缀自动机.树形DP) 水是水,但是写出了不少问题,因此写一发博客. https://www.luogu.or ...

  6. [NOI2016] 优秀的拆分 题解

    [NOI2016] 优秀的拆分 题解 link 题意 \(T\) 组询问,每组一个字符串 \(s\) 求 \(s\) 所有字串分成 \(AABB\) 的方案数之和. \(A,B\) 为非空串. 题解 ...

  7. NOI2016 优秀的拆分(图解)

    如果一个字符串可以被拆分为 AABB 的形式,其中 A和 B是任意非空字符串,则我们称该字符串的这种拆分是优秀的. 例如,对于字符串 aabaabaa,如果令 A=aab,B=a,我们就找到了这个字符 ...

  8. luogu P2216 [HAOI2007]理想的正方形 递推+ST表

    题意:有一个a*b的整数组成的矩阵,现请你从中找出一个n*n的正方形区域,使得该区域所有数中的最大值和最小值的差最小. 数据规模: (1)矩阵中的所有数都不超过1,000,000,000 (2)20% ...

  9. 【BZOJ 2119】 2119: 股市的预测 (后缀数组+分块+RMQ)

    2119: 股市的预测 Time Limit: 10 Sec  Memory Limit: 259 MB Submit: 404  Solved: 188 Description 墨墨的妈妈热爱炒股, ...

最新文章

  1. 2021年大数据常用语言Scala(二十七):函数式编程 聚合操作
  2. 可旋转的2K显示器,写代码逼格要到位,免费包邮送到家
  3. socket recv 服务端阻塞 python_网络编程(基于socket编程)
  4. 互联网人的生存指南 | 每日趣闻
  5. yum php56w_yum安装PHP/yum升级PHP
  6. 为什么分库分表后不建议跨分片查询
  7. 几种xml读取方法比较
  8. 《Python从小白到大牛》第7章 运算符
  9. 数据结构——最小生成树之克鲁斯卡尔算法(Kruskal)
  10. P3387-【模板】缩点【tarjan,强联通分量,DAGdp】
  11. Python高级——property属性
  12. JavaScriptjQuery.动态删除元素
  13. 使用JSON Viewer直观查看JSON数据
  14. ArcGIS中栅格数据的金字塔详解
  15. [转]飞秋使用说明与常见问题解决方法
  16. 轻松搞出一个云盘项目(一),一般人我不告诉哦。
  17. NBA比赛数据table表格
  18. C++软件调试与异常排查从入门到精通系列汇总
  19. WinDbg实践--入门篇
  20. 电子计算机上的GT是什么意思,计算机上的“GT”是什么意思啊

热门文章

  1. c语言vs开发小型数据库,用C语言开发小型数据库管理系统代码
  2. linux安装oracle 操作系统内核参数 aio,Oracle Study之案例--安装Oracle内核参数配置
  3. Linux下cat命令各种用法
  4. Delphi中的容器类
  5. NHibernate快速起步
  6. asp.net中上传图片并生成小图片,自动添加水印的代码 .
  7. 给定两个字符串形式的非负整数 num1 和num2 ,计算它们的和。
  8. 参数匹配顺序——Python学习之参数(三)
  9. hdu-2209 dfs
  10. java文件名特殊字符_Java 8:用名字读取特殊字符的文件