[SDOI2016] 生成魔咒(后缀数组SA + st表 + set)动态不同子串个数

problem

luogu-P4070

魔咒串由许多魔咒字符组成,魔咒字符可以用数字表示。例如可以将魔咒字符 1,21,21,2 拼凑起来形成一个魔咒串 [1,2][1,2][1,2]

一个魔咒串 S 的非空字串被称为魔咒串 S 的生成魔咒。

例如 S=[1,2,1]S=[1,2,1]S=[1,2,1] 时,它的生成魔咒有 [1],[2],[1,2],[2,1],[1,2,1][1],[2],[1,2],[2,1],[1,2,1][1],[2],[1,2],[2,1],[1,2,1] 五种。

S=[1,1,1]S=[1,1,1]S=[1,1,1] 时,它的生成魔咒有 [1],[1,1],[1,1,1][1],[1,1],[1,1,1][1],[1,1],[1,1,1] 三种,最初 S 为空串。

共进行 nnn 次操作,每次操作是在 SSS 的结尾加入一个魔咒字符。每次操作后都需要求出,当前的魔咒串 SSS 共有多少种生成魔咒。

solution

本质不同的子串个数,是后缀数组经典运用,∑n−i+1−hi=n(n+1)2−∑hi\sum n-i+1-h_i=\frac{n(n+1)}{2}-\sum h_ini+1hi=2n(n+1)hi

考虑每次在字符串末尾加入一个数字的话,我们就需要每次重新求一遍所有的后缀,因为全都变了。hhh 的变化也是动态不定的。

但如果反过来,每次在字符串开头加入一个数字的话,相当于只是多加了一个后缀。hhh 的变化是 O(1)O(1)O(1) 的。

所以我们将 nnn 个数组成的字符串反转,提前求出每个后缀的排名,hhh 数组,建立 ststst 表。

倒着枚举 i=n∼1i=n\sim 1i=n1,加入 iii 开头的后缀,然后查询与其最相近的后缀,即 rnk[i]rnk[i]rnk[i] 的前后缀。

重复的子串个数为 cnt+lcp(pre,rnk[i])+lcp(rnk[i],nxt)−lcp(pre,nxt)cnt+lcp(pre,rnk[i])+lcp(rnk[i],nxt)-lcp(pre,nxt)cnt+lcp(pre,rnk[i])+lcp(rnk[i],nxt)lcp(pre,nxt)

setsetset 维护 rnkrnkrnk 数组即可,当然也可以链表等各种快速查前后缀的工具。

code

#include <bits/stdc++.h>
using namespace std;
#define maxn 100005
#define int long long
int h[maxn], s[maxn], x[maxn], sa[maxn], id[maxn], tot[maxn], rnk[maxn << 1];
int lg[maxn], st[maxn][20];
set < int > NB;
int n, m;void SA() {for( int i = 1;i <= n;i ++ ) tot[x[i] = s[i]] ++;for( int i = 1;i <= m;i ++ ) tot[i] += tot[i - 1];for( int i = n;i;i -- ) sa[tot[x[i]]--] = i;for( int k = 1;k <= n;k <<= 1 ) {int num = 0;for( int i = n - k + 1;i <= n;i ++ ) id[++ num] = i;for( int i = 1;i <= n;i ++ ) if( sa[i] > k ) id[++ num] = sa[i] - k;memset( tot, 0, sizeof( tot ) );for( int i = 1;i <= n;i ++ ) tot[x[i]] ++;for( int i = 1;i <= m;i ++ ) tot[i] += tot[i - 1];for( int i = n;i;i -- ) sa[tot[x[id[i]]]--] = id[i];for( int i = 1;i <= n;i ++ ) rnk[i] = x[i];x[sa[1]] = num = 1;for( int i = 2;i <= n;i ++ )x[sa[i]] = (rnk[sa[i]] == rnk[sa[i - 1]] and rnk[sa[i] + k] == rnk[sa[i - 1] + k]) ? num : ++ num;if( n == num ) break;m = num;}
}void height() {for( int i = 1;i <= n;i ++ ) rnk[sa[i]] = i;for( int i = 1, k = 0;i <= n;i ++ ) {if( rnk[i] == 1 ) continue;if( k ) k --;int j = sa[rnk[i] - 1];while( i + k <= n and j + k <= n and s[i + k] == s[j + k] ) k ++;h[rnk[i]] = k;}
}void ST() {lg[0] = -1; for( int i = 1;i <= n;i ++ ) lg[i] = lg[i >> 1] + 1;for( int i = 1;i <= n;i ++ ) st[i][0] = h[i];for( int j = 1;(1 << j) <= n;j ++ )for( int i = 1;i + (1 << j) - 1 <= n;i ++ )st[i][j] = min( st[i][j - 1], st[i + (1 << j - 1)][j - 1] );
}int lcp( int l, int r ) {l ++; int i = lg[r - l + 1];return min( st[l][i], st[r - (1 << i) + 1][i] );
}signed main() {scanf( "%lld", &n );for( int i = 1;i <= n;i ++ ) scanf( "%lld", &s[i] ), x[i] = s[i];sort( x + 1, x + n + 1 );m = unique( x + 1, x + n + 1 ) - x - 1;for( int i = 1;i <= n;i ++ ) s[i] = lower_bound( x + 1, x + m + 1, s[i] ) - x;reverse( s + 1, s + n + 1 );SA();height();ST();NB.insert( 0 );NB.insert( n + 1 );int ans = 0;for( int i = n;i;i -- ) {NB.insert( rnk[i] );auto it = NB.find( rnk[i] );auto pre = it; -- pre;auto nxt = it; ++ nxt;ans = ans - lcp( *pre, *nxt ) + lcp( *pre, rnk[i] ) + lcp( rnk[i], *nxt );printf( "%lld\n", (n - i + 1) * (n - i + 2) / 2 - ans );}return 0;
} 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/316282.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

P4248 [AHOI2013]差异

P4248 [AHOI2013]差异 题意&#xff1a; ∑1≤i<j≤nlen(Ti)len(Tj)−2∗lcp(Ti,Tj)\sum_{1\leq i<j\leq n}len(T_{i})len(T_{j})-2*lcp(T_{i},T_{j})∑1≤i<j≤n​len(Ti​)len(Tj​)−2∗lcp(Ti​,Tj​) 题解&#xff1a; ∑1≤i<j≤nlen(Ti)len(Tj)\sum_{1\le…

从高德采集最新的省市区三级坐标和行政区域边界,用js在浏览器中运行

本文描述的是对国家统计局于2019-01-31发布的《2018年统计用区划代码和城乡划分代码(截止2018年10月31日)》中省市区三级的坐标和行政区域边界的采集。本文更新&#xff08;移步查阅&#xff09;&#xff1a;19-04-15 新采集了2018的省市区三级的坐标和行政区域边界数据csv格式…

[JSOI2016] 最佳团体(0/1分数规划 + 树形dp)

problem luogu-P4322 solution 假设每个人是否被招募&#xff0c;用 xi{0,1}x_i\{0,1\}xi​{0,1} 代替&#xff0c;max⁡∑pi∗xi∑si∗xi\max\frac{\sum p_i*x_i}{\sum s_i*x_i}max∑si​∗xi​∑pi​∗xi​​。 0/10/10/1 分数规划标准式子。 二分答案 ans∑pi∗xi∑si∗…

Display Substring

Display Substring 题意&#xff1a; 一个长度为n的字符串&#xff0c;每个字符有自己的价值&#xff0c;求第k小价值的不重复子串价值 题解&#xff1a; 首先众所周知&#xff0c;所有子串都可以用后缀的前缀来表示&#xff0c;这就和后缀数组扯上关系了 我们可以直接二分…

使用 DotNet CLI 创建自定义的 WPF 项目模板

描述当我们安装完 DotNetCore 3.0 版本的 SDK 后&#xff0c;我们就可以创建基于 DotNetCore 的 WPF 项目模板&#xff0c;通过如下 CLI 可以方便快捷的创建并运行我们的项目&#xff1a;Copydotnet new wpf -n WpfAppcd WpfAppdotnet restoredotnet run做过 WPF 开发的朋友都知…

[省选联考 2020 A/B 卷] 信号传递(状压dp + 卡空间)

problem luogu-P6622 一条道路上从左至右排列着 mmm 个信号站&#xff0c;初始时从左至右依次编号为 1,2,…,m1,2,\dots,m1,2,…,m&#xff0c;相邻信号站之间相隔 111 单位长度。 每个信号站只能往它右侧的任意信号站传输信号&#xff08;称为普通传递&#xff09;&#xf…

SP687 REPEATS - Repeats(暂时不会)

SP687 REPEATS - Repeats 题意&#xff1a; 给定字符串&#xff0c;求重复次数最多的连续重复子串 题解&#xff1a; 论文题&#xff0c;暂时不会&#xff0c;搞不清楚原理 代码&#xff1a;

[翻译] ASP.NET Core 利用 Docker、ElasticSearch、Kibana 来记录日志

一步一步指导您使用 ElasticSearch, Kibana, ASP.NET Core 2.1 和 Docker 来记录日志在本教程中&#xff0c;我将向您展示如何启动和运行 ElasticSearch&#xff0c;Kibana 和 ASP.NET Core 2.1在开始之前&#xff0c;让我们来看看 ElasticSearch&#xff0c;Kibana 和 Serilog…

[省选联考 2020 A 卷] 作业题(欧拉反演 + 矩阵树定理 + 高斯消元)

problem luogu-P6624 小 W 刚刚在离散数学课学习了生成树的知识&#xff1a;一个无向图 G(V,E)G(V,E)G(V,E) 的生成树 TTT 为边集 EEE 的一个大小为 ∣V∣−1|V|-1∣V∣−1 的子集&#xff0c;且保证 TTT 的生成子图在 GGG 中连通。 小 W 在做今天的作业时被这样一道题目难住…

P4070 [SDOI2016]生成魔咒

P4070 [SDOI2016]生成魔咒 题意&#xff1a; 有n个字符xi&#xff0c;每次在S的末尾加入一个字符&#xff0c;(一开始S为空)&#xff0c;每次加入xi后的不相同字串有多少个 题解&#xff1a; 做这个题首先要会后缀数组P3809 【模板】后缀排序&#xff0c;还要知道不同的子串…

【学习笔记】WQS二分详解及常见理解误区解释

文章目录应用分析算法分析WQS二分精髓的两点细节&#xff08;博客重点&#xff01;&#xff09;真题分析[国家集训队]Tree Ⅰ忘情星际广播网上很多博客写得模模糊糊的&#xff0c;对我这个新手可是一点都不友好。 昨天一天都在研究这个东西&#xff0c;分享一下自己的拙见。 百…

ASP.NET Core中HTTP管道和中间件的二三事

本文出自《从零开始学ASP.NET CORE MVC》推荐文章&#xff1a;中间件是什么&#xff1f;在.NET Core中的工作原理又是怎样的呢&#xff1f;配置ASP.NET Core请求(Request)处理管道在本视频中&#xff0c;我们将讨论使用中间件组件为asp.net core 应用程序配置请求处理管道。作为…

Codeforces Round #737 (Div. 2)

Codeforces Round #737 (Div. 2) 题号题目知识点AEzzat and Two Subsequences思维&#xff08;略&#xff09;BMoamen and k-subarrays思维(略)CMoamen and XOR二进制DEzzat and Grid线段树思维EAssiut Chess

非平凡回路(bfs)

problem 题目描述 给定一张 nnn 个点的无向图&#xff0c;定义经过一个点 uuu 的非平凡回路为一条从 uuu 出发回到 uuu 的路径&#xff0c;并且至少包含一个简单环。 对于每个点求出经过它的最小非平凡回路长度 lll。 考虑到这个问题很困难&#xff0c;因此你只需要求出 ⌈…

cf1557 C. Moamen and XOR

cf1557 C. Moamen and XOR 题意&#xff1a; 一个n位数&#xff0c;每一位小于2k2^k2k,如果a1&a2&…an>a1⊕a2…⊕an,则获胜 现在给你n和k&#xff0c;问能构造多少个序列是获胜的 题解&#xff1a; 奇偶分类二进制考虑 我们现在认为每个数的第k位都是1 如果n为…

.Net Core Razor 预编译,动态编译,混合编译

预编译预编译是ASP .Net Core的默认方式。在发布时&#xff0c;默认会将系统中的所有Razor视图进行预编译。编译好的视图DLL统一命名为 xxx.PrecompiledViews.dll 或者 xxx.Views.dll动态编译将项目整个配置成动态编译很简单&#xff0c;添加一个配置项目MvcRazorCompileOnPubl…

[CodeForces gym 101630 J] 过路费(最短路)

problem 给定一张图 nnn 个点 mmm 条边&#xff0c;并给定阈值 kkk&#xff0c;以及起终点 s,ts,ts,t。 然后每条边经过都需要支付 www 的花费&#xff0c;形如 (u,v,w)(u,v,w)(u,v,w) 格式给出。 求 s→ts\rightarrow ts→t 的最小花费。 最小花费定义如下&#xff1a; 如…

cf1557D. Ezzat and Grid

cf1557D. Ezzat and Grid 题意&#xff1a; 有n行&#xff0c;每行有10910^9109列&#xff0c;仅仅由0和1构成 现在给你1的存在位置&#xff0c;(i,l,r)表示第i行的第l列到第r列全为1 你可以删除任意一行i&#xff0c;删除后&#xff0c;第i-1行和第i1行为相邻 现在我们要求求…

一张图来看看.NETCore和前后端技术的演进之路

一张图2019年3月10日&#xff0c;在长沙.NET 技术社区组织的技术沙龙《.NET Core和前后端分离那些事儿》上&#xff0c;我们曾经试图通过一系列抽丝剥茧的过程来引导大家在这条基于.NET Core的前后端分离有关的技术路线上持续发散&#xff0c;由于各种原因未能成功&#xff0c;…

【学习笔记】我命由天不由我之随机化庇佑 —— 爬山法 和 模拟退火法

以下均假设最优解是在最低点。 爬山法 爬山算法是一种局部择优的方法&#xff0c;采用启发式方法&#xff0c;是对深度优先搜索的一种改进&#xff0c;它利用反馈信息帮助生成解的决策。 直白地讲&#xff0c;就是当目前无法直接到达最优解&#xff0c;但是可以判断两个解哪…