「NOI2016」优秀的拆分

这不是个SAM题,只是个LCP题目

95分的Hash很简单,枚举每个点为开头和末尾的AA串个数,然后乘一下之类的。

考虑怎么快速求“每个点为开头和末尾的AA串个数”

考虑枚举A的长度,然后在序列中每|A|个位置放一个关键点,这样每个AA至少都经过了一个关键点。

然后求相邻两个关键点的lcs,lcp,画画图匹配一下,可以把区间内的都求出来了。

可以Hash二分或者sa或者sam


Code:

#include <cstdio>
#include <cstring>
#include <algorithm>
#define ll long long
using std::min;
const int N=120010;
struct SAM
{
int head[N],to[N],Next[N],cnt;
void add(int u,int v){to[++cnt]=v,Next[cnt]=head[u],head[u]=cnt;}
int dfn[N],st[18][N],Log[N],dep[N],pos[N],clock;
void dfs(int now)
{
st[0][dfn[now]=++clock]=now;
for(int i=head[now];i;i=Next[i])
dep[to[i]]=dep[now]+1,dfs(to[i]),st[0][++clock]=now;
}
int LCA(int x,int y)
{
x=dfn[x],y=dfn[y];
if(x>y) std::swap(x,y);
int d=Log[y+1-x];
x=st[d][x],y=st[d][y-(1<<d)+1];
return dep[x]<dep[y]?x:y;
}
int len[N],par[N],ch[N][26],las=1,tot=1;
void extend(int c)
{
int now=++tot,p=las;
len[now]=len[p]+1;
while(p&&!ch[p][c]) ch[p][c]=now,p=par[p];
if(!p) par[now]=1;
else
{
int x=ch[p][c];
if(len[x]==len[p]+1) par[now]=x;
else
{
int y=++tot;
len[y]=len[p]+1;
par[y]=par[x];
memcpy(ch[y],ch[x],sizeof ch[y]);
while(p&&ch[p][c]==x) ch[p][c]=y,p=par[p];
par[x]=par[now]=y;
}
}
las=now;
}
void init(char *s,int typ)
{
int n=strlen(s+1);
for(int i=1;i<=n;i++) extend(s[i]-'a'),pos[typ?n+1-i:i]=las;
for(int i=1;i<=tot;i++) add(par[i],i);
clock=0,dep[1]=1,dfs(1);
Log[0]=-1;for(int i=1;i<=clock;i++) Log[i]=Log[i>>1]+1;
for(int j=1;j<=17;j++)
for(int i=1;i<=clock-(1<<j)+1;i++)
{
int x=st[j-1][i],y=st[j-1][i+(1<<j-1)];
st[j][i]=dep[x]<dep[y]?x:y;
}
}
void clear()
{
memset(ch,0,sizeof ch);
memset(par,0,sizeof par);
memset(len,0,sizeof len);
memset(head,0,sizeof head);
cnt=0,las=tot=1;
}
int query(int x,int y)
{
return len[LCA(pos[x],pos[y])];
}
}LCS,LCP;
int d[N],f[N],g[N];
void work(char *s,int *f)
{
int n=strlen(s+1);
LCS.init(s,0);
std::reverse(s+1,s+n+1);
LCP.init(s,1);
for(int l=1;l<=n;l++)
{
for(int i=1;i+l<=n;i+=l)
{
int a=min(LCS.query(i,i+l),l),b=min(LCP.query(i,i+l),l);
if(a+b-1<l) continue;
int ss=i-a+1,tt=ss+a+b-l-1;
++d[ss+l*2-1],--d[tt+l*2];
}
}
for(int i=1;i<=n;i++) f[i]=f[i-1]+d[i];
memset(d,0,sizeof d);
LCP.clear(),LCS.clear();
}
char s[N];
int main()
{
int T;scanf("%d",&T);
while(T--)
{
memset(f,0,sizeof f);
memset(g,0,sizeof g);
scanf("%s",s+1);
int n=strlen(s+1);
work(s,f);
work(s,g);
std::reverse(g+1,g+1+n);
ll ans=0;
for(int i=1;i<=n;i++) ans=ans+f[i-1]*g[i];
printf("%lld\n",ans);
}
return 0;
}

2019.3.15

「NOI2016」优秀的拆分 解题报告的更多相关文章

  1. 「NOI2016」循环之美 解题报告

    「NOI2016」循环之美 对于小数\(\frac{a}{b}\),如果它在\(k\)进制下被统计,需要满足要求并且不重复. 不重复我们确保这个分数是最简分数即\((a,b)=1\) 满足要求需要满足 ...

  2. LOJ#2083. 「NOI2016」优秀的拆分

    $n \leq 30000$的字符串,问其所有子串的所有AABB形式的拆分有多少种.$t \leq 10$组询问. $n^3$过80,$n^2$过95,鬼去写正解.. $n^2$:先枚举一次算每个位置 ...

  3. 洛谷 P4714 「数学」约数个数和 解题报告

    P4714 「数学」约数个数和 题意(假):每个数向自己的约数连边,给出\(n,k(\le 10^{18})\),询问\(n\)的约数形成的图中以\(n\)为起点长为\(k\)的链有多少条(注意每个点 ...

  4. 「NOI2013」树的计数 解题报告

    「NOI2013」树的计数 这什么神题 考虑对bfs重新编号为1,2,3...n,然后重新搞一下dfs序 设dfs序为\(dfn_i\),dfs序第\(i\)位对应的节点为\(pos_i\) 一个暴力 ...

  5. 「FJOI2018」领导集团问题 解题报告

    「FJOI2018」领导集团问题 题意:给你一颗\(n\)个点的带点权有根树,选择一个点集\(S\),使得点集中所有祖先的点权$\le \(子孙的点权,最大化\)|S|$(出题人语死早...) 一个显 ...

  6. 「SP25784」BUBBLESORT - Bubble Sort 解题报告

    SP25784 BUBBLESORT - Bubble Sort 题目描述 One of the simplest sorting algorithms, the Bubble Sort, can b ...

  7. 「SP122」STEVE - Voracious Steve 解题报告

    SP122 STEVE - Voracious Steve 题意翻译 Problem Steve和他的一个朋友在玩游戏,游戏开始前,盒子里有 n个甜甜圈,两个人轮流从盒子里抓甜甜圈,每次至少抓 1个, ...

  8. 「Luogu」[JSOI2007]字符加密 解题报告

    题面 思路: 作为一个后缀数组的初学者,当然首先想到的是后缀数组 把\(s\)这个串首尾相接,扩展为原来的两倍,就能按后缀数组的方法处理 证明: 神仙一眼就看出这是后缀的裸题,我这个蒟蒻想了半天想不出 ...

  9. 「P5004」专心OI - 跳房子 解题报告

    题面 把\(N\)个无色格子排成一行,选若干个格子染成黑色,要求每个黑色格子之间至少间隔\(M\)个格子,求方案数 思路: 矩阵加速 根据题面,这一题似乎可以用递推 设第\(i\)个格子的编号为\(i ...

随机推荐

  1. 转:MD5(Message-Digest Algorithm 一种哈希算法)

    什么是MD5算法 MD5讯息摘要演算法(英语:MD5 Message-Digest Algorithm),一种被广泛使用的密码杂凑函数,可以产生出一个128位元(16位元组)的散列值(hash val ...

  2. Spring Boot 框架学习 (一)配置并运行Spring Boot 框架

    下载开发工具: 下载完成打开以后,第一步检查环境 查看jdk是否配置: 接着一定要注意,maven通常情况下它是没有给你配置的,要自行配置: 右键新建: 然后依赖选择web.跟Mybatis就行了. ...

  3. Guava Cache源码详解

    目录 一.引子 二.使用方法 2.1 CacheBuilder有3种失效重载模式 2.2 测试验证 三.源码剖析 3.1 简介 3.2 源码剖析 四.总结 优点: 缺点: 正文 回到顶部 一.引子 缓 ...

  4. python数据结构与算法第十天【插入排序】

    1.插入排序的原理 2.代码实现 def insert_sort(alist): # 从第二个位置,即下标为1的元素开始向前插入 for i in range(1, len(alist)): # 从第 ...

  5. 一、VS2017支持Github

    选择 工具-->扩展和更新,搜索GitHub,安装GitHub的VS插件 安装完插件,打开视图-->团队资源管理器,我们可以看到Git插件菜单.通过菜单我们可以新建Git存储库,可以提交修 ...

  6. LodopJS文档式模版的加载和赋值

    Lodop模版有两种方法,一种是传统的JS语句,可以用JS方法里的eval来执行,一种是文档式模版,是特殊格式的base64码,此篇博文介绍文档式模版的加载,文档式模版的生成以及传统JS模版的生成加载 ...

  7. 【理论】X理论、Y理论及Z理论

      道格拉斯·麦格雷戈(Douglas Mcgregor)把对人的基本假设作了区分,即X理论和Y理论.X理论认为:人们总是尽可能地逃避工作,不愿意承担责任,因此要想有效地进行管理,实现组织的目标,就必 ...

  8. java开发支付宝支付详细流程_demo的运行

    首先我要吐槽一下支付宝的开放平台简直就是一个迷宫,赞同的顶一下,下面我把要下载的地址给贴出来要不真不好找: 一.准备工作 1.签名工具下载 https://docs.open.alipay.com/2 ...

  9. 使用styled-components实现CSS in JS

    前面的话 使用jsx语法可以实现HTML in JS,使用svgr可以实现svg in JS,使用styled-components可以实现CSS in JS.这样,使用react开发,就变成了使用J ...

  10. U68641 划水(swim.pas/c/cpp)

    U68641 划水(swim.pas/c/cpp) 题目背景 小小迪带你划水. 题目描述 原题 输入输出格式 输入格式: 第一行一个数 T. 接下来 T 行每行一个数表示 n 输出格式: 输出 T 行 ...