题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=4278 题解: 居然把后缀数组写成n^2的..我真厉害.. 想了无数种方法,最后发现就是比后缀字典序排名,后缀数组即可 注意每个字符串的结尾处要加上一个\(\inf\), 因为相当于要把空位尽量后移使得非空位集中在前面 代码 #include<cstdio> #include<cstdlib> #include<cstring> #include<alg…
Code: #include <bits/stdc++.h> #define setIO(s) freopen(s".in", "r", stdin) #define maxn 4000000 using namespace std; int n, m, tot; int arr[maxn], height[maxn], A[maxn]; namespace SA { int rk[maxn], tp[maxn], sa[maxn], tax[maxn]…
直接归并,然后如果哪边的后缀字典序比较小就去哪边,然后就可以后缀数组 博客传送门- 但是本蒟蒻不会后缀数组 Upd:Upd:Upd:现在会了233.一道差不多的题:BZOJ 1692: [Usaco2007 Dec]队列变换 于是就hash后二分找相同的最长区间,然后比较后一个谁更小- 时间复杂度O(nlogn)O(nlogn)O(nlogn). 注意先在最后加一个极大值.因为如果一个序列A到末尾刚好与序列B的一段相等,那么一定是取B更优,因为B后面可能有更小的. hack数据 4 2 2 2…
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4278 因为每次要放后缀较小的那个,所以把两个序列放在一起排序吧.改一改模板. 其实要改的地方就是让后面序列那部分不要在倍增的时候更新前面序列那部分. 考虑 4 和 43 ,应该是 43 比 4 小:因为放了单独的 4 的话就只能放 43 ,而放了 43 的 4 的话可以放 3 再放单独的 4 . 即,前缀相等的话短的比较大.长的比较小.把 n-k+1 ~ n 的那个赋值放在 if( sa[…
[BZOJ4278][ONTAK2015]Tasowanie Description 给定两个数字串A和B,通过将A和B进行二路归并得到一个新的数字串T,请找到字典序最小的T. Input 第一行包含一个正整数n(1<=n<=200000),表示A串的长度. 第二行包含n个正整数,其中第i个数表示A[i](1<=A[i]<=1000). 第三行包含一个正整数m(1<=m<=200000),表示B串的长度. 第四行包含m个正整数,其中第i个数表示B[i](1<=B[…
给出两个字符串 A B 让我们对其二路归并 求出能够归并出的最小字典序. 考虑后缀数组 不难发现我们将B直接连在A上会出现问题 问题是 A串剩下的和B串完全相同了 那么此时比大小就会用到B的部分 这是不合理的. 考虑怎么解决这个问题 如果比到了末尾之后的数字 那么较长的串答案不会更差 所以考虑在中间加一个INF. 对于B也有这种情况 那么需要在末尾也加一个INF 即可解决问题 可以证明这样做是最优的. 具体的 可以这样思考 我们之所以让较长的优先 是考虑到了较长的第一个决定字典序的位置上的字符…
题链: http://www.lydsy.com/JudgeOnline/problem.php?id=4278 题解: 把两个串连接起来,用一个大数连接(必须要用大数).倍增算法求出后缀排名.然后两个指针指向A,B串,每次比较两个后缀的大小,优先取出小的那个后缀的首字母,然后对应指针向后移动一位. 代码: #include<cstdio> #include<cstring> #include<iostream> #define MAXN 450000 #define…
题目 求两数组归并后的数组最小字典序排列. 嘛,可能本人在贪心这块还是太弱了(或者说什么都弱),如果不知道是字符串题估计也想不起来用sa. 显然看得出归并时字典序小的那个数组先往里面加,这就是要比较两数组后缀的rank,方法就把两串相拼做后缀排序后比较. 这里附下贪心正确性证明,反正我不太会,只是感性认识一下. Upd:突然想起来这题其实可以hash+二分比较,码量稍小,不想写了 #include<bits/stdc++.h> using namespace std; typedef long…
[题意] 给定两个字符串,求二路归并后最小字典序的字符串. [思路] 连接两个字符串后求出rank数组.通过比较rank数组进行二路归并. [代码] #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define FOR(a,b,c) for(int a=b;a<=c;a++) using namespace std; typedef long long…
4278: [ONTAK2015]Tasowanie Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 164  Solved: 80[Submit][Status][Discuss] Description 给定两个数字串A和B,通过将A和B进行二路归并得到一个新的数字串T,请找到字典序最小的T. Input 第一行包含一个正整数n(1<=n<=200000),表示A串的长度. 第二行包含n个正整数,其中第i个数表示A[i](1<=A[i]…
BZOJ_4278_[ONTAK2015]Tasowanie_后缀数组 Description 给定两个数字串A和B,通过将A和B进行二路归并得到一个新的数字串T,请找到字典序最小的T. Input 第一行包含一个正整数n(1<=n<=200000),表示A串的长度. 第二行包含n个正整数,其中第i个数表示A[i](1<=A[i]<=1000). 第三行包含一个正整数m(1<=m<=200000),表示B串的长度. 第四行包含m个正整数,其中第i个数表示B[i](1&l…
题目大意 给定两个数字串A和B,通过将A和B进行二路归并得到一个新的数字串T,请找到字典序最小的T.\(len \leq 200000\) 题解 我们从归并排序的角度去想,每次把两者之一较小的取出来 遇到相等的元素的时候,排序时取那个都是一样的. 但是在这道题中我们是求字典序最小,这就不一样了. 我们不能任意取,这一步的决策其实是由后面的数字的大小决定的 怎么说呢... 方法蕴藏在这三张图里了,自己去悟吧. 黑色箭头表示选取,黑色圆圈表示确定选取序列的理由. 迭代第一次 迭代第二次 迭代第三次…
Tasowanie bzoj-4278 ONTAK-2015 题目大意:给定两个字符串,求两个字符串二路归并之后生成的字典序最小的字符串是什么. 注释:$1\le len_1,len_2\le 2\cdot 10^5$. 想法: 和队列变换比较像啊. 我们将两个串接在一起然后建立后缀数组即可. 紧接着像那道题一样,在$sa$上弄两个指针贪心地移动即可. Code: #include <iostream> #include <cstdio> #include <cstring&…
3473: 字符串 Description 给定n个字符串,询问每个字符串有多少子串(不包括空串)是所有n个字符串中至少k个字符串的子串? Input 第一行两个整数n,k. 接下来n行每行一个字符串. Output 一行n个整数,第i个整数表示第i个字符串的答案. Sample Input 3 1 abc a ab Sample Output 6 1 3 HINT 对于 100% 的数据,1<=n,k<=10^5,所有字符串总长不超过10^5,字符串只包含小写字母. [分析] 这道题用后缀数…
3172: [Tjoi2013]单词 Time Limit: 10 Sec   Memory Limit: 512 MB Submit: 268   Solved: 145 [ Submit][ Status] Description 某人读论文,一篇论文是由许多单词组成.但他发现一个单词会在论文中出现很多次,现在想知道每个单词分别在论文  中出现多少次. Input 第一个一个整数N,表示有多少个单词,接下来N行每行一个单词.每个单词由小写字母组成,N<=200,单词长度不超过10^6 Out…
集训讲字符串的时候我唯一想出正解的题-- 链接 BZOJ 2865 题面 给出一个长度为n (n <= 5e5) 的字符串,对于每一位,求包含该位的.最短的.在原串中只出现过一次的子串. 题解 "只出现过一次",想到后缀数组,后缀数组可以求出以第i位开头的最短的在原串中只出现过一次的子串--它的长度是min(height[rank[i]], height[rank[i] + 1) + 1. 所以我们枚举每个位置i,找到这个串,然后考虑它的贡献: 对于这个串之内的位置,答案可以用这…
BZOJ 3230 相似子串 题面 题解 首先我们要知道询问的两个子串的位置. 先正常跑一遍后缀数组并求出height数组. 对于每一个后缀suffix(i),考虑以i开头的子串有多少是之前没有出现过的,也就是考虑左端点在i.右端点在什么范围内时这个子串没有出现过--答案是右端点在[i + height[i] - 1, n]范围内时这个子串没出现过,即右端点在没有被"i与排在前一个的后缀的公共前缀"覆盖的部分时,这个子串没有出现过. 那么我们记录以每个i开头的新子串的数量,求前缀和,然…
这道题各位大神好像都是用后缀自动机做的?.....蒟蒻就秀秀智商写一写后缀数组解法..... 求出Height数组后, 我们枚举每一位当做子串的开头. 如上图(x, y是height值), Heights数组中相邻的3个后缀, 假如我们枚举s2的第一个字符为开头, 那我们发现, 长度至少为len = max(x, y)+1, 才能满足题意(仅出现一次). 这个很好脑补...因为s2和其他串的LCP是RMQ, 肯定会<=LCP(s1,s2)或<=LCP(s2,s3). 然后就用len去更新s2中…
题目大意:给定一个n个单词的文章,求每一个单词在文章中的出现次数 文章长度<=10^6(不是单词长度<=10^6,不然读入直接超时) 首先将全部单词用空格连接成一个字符串.记录每一个单词的起始位置和长度 然后求后缀数组,对于每一个单词后缀数组中一定有连续一段后缀以这个单词开头,我们通过一開始记录的起始位置找到这个单词的后缀,然后左右端点二分答案,满足左右端点之间的后缀与原单词的LCP都当与等于原单词长度就可以 时间复杂度O(nlogn) #include<cstdio> #incl…
3238: [Ahoi2013]差异 Time Limit: 20 Sec  Memory Limit: 512 MB Description Input 一行,一个字符串S Output 一行,一个整数,表示所求值 Sample Input cacao Sample Output 54 HINT 2<=N<=500000,S由小写英文字母组成 Source 后缀数组+单调栈水过... #include<map> #include<cmath> #include<…
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3230 作出后缀数组,从 LCP 看每个位置对于本质不同子串的贡献,而且他们已经按前面部分排好序了,所以直接在 sa[ ] 上二分就能找到询问的子串. 找最长公共前缀就用 ht[ ] 和子串的长度比较就行.找最长公共后缀就一开始把原串翻转,做出翻转后的 ht[ ] ,就能查询了. 也可以二分一个最长公共后缀的位置,然后用正常的 ht[ ] 判断. 注意 long long . #includ…
题目大意 给定后缀数组sa,要求构造出满足sa数组的字符串.或输出无解\(n\leq 5*10^5\) 题解 我们按照字典序来考虑每个后缀 对于\(Suffix(sa[i])\)和\(Suffix(sa[i-1])\) 我们一定知道\(Suffix(sa[i-1])<Suffix(sa[i])\). 如果我们有\(Suffix(sa[i-1]+1)<Suffix(sa[i]+1)\) 那么\(sa[i]\)和\(sa[i-1]\)两个位置上的字符相等时也满足条件 那么从贪心的角度来讲我们就让\…
题目的Source好有趣. 我们求出SA,然后求出每一个后缀中与前面本质不同的字符串的个数. 然后二分求出当前的字符串. 然后就是正反两次后缀数组求LCP的裸题了. 要注意,这时两个串的起点可能会相同,所以需要判掉. 无论读入还是输出都有可能爆long long,要注意 #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace s…
传送门 解题思路 其实题目挺好想的.首先子串排名可以由后缀数组求得,因为不算重复的,所以后缀数组的每个后缀排名的去掉\(lcp\)的前缀排名为当前后缀的子串排名.这样就可以预处理出每个后缀的\(l,r\),查询的时候二分出来属于哪个后缀,用\(rmq\)求个\(lcp\).倒过来处理的式子比较麻烦,要先将排名转化成位置,然后找到对应的倒过来的位置,最后在转化为排名,具体看代码. 代码 #include<iostream> #include<cstdio> #include<c…
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4278 每次取两个后缀中字典序较小的那个的首字符: 注意超出去的部分是 inf 而不是 0,因为如果到了比较超出去部分的时候,那就是一个串走到了末尾而另一个没有(或者都到末尾,不过都到末尾就随便选啦),而且两个后缀的 LCP 顶到了末尾: 这时选长度较长的比较优,因为反正 LCP 处一样,先选较短的等选完以后还是得过来,不如先选较长的,也许后面还出现更优的. 代码如下: #include<i…
BZOJ \(Description\) 给定两个串\(S,T\)以及一个数\(k\),求\(T\)中有多少个子串,满足和\(S\)的编辑距离不超过\(k\). \(|S|+|T|\leq10^5,\ k\leq 5\). \(Solution\) 考虑枚举\(T\)的每个后缀\(i\)(注意后缀是指啥= =),求后缀\(i\)中有哪些前缀满足条件. 怎么处理编辑距离呢?\(k\)很小,直接搜. 设\(S,T\)分别匹配到\(x,y\)位置,可以用\(SA\)求\(LCP(x,y)\),然后直接…
传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=1692 题意: 给出一个长度为N的字符串,每次可以从串头或串尾取一个字符,添加到新串中,使新串的字典序最小. 做法: 经过推导(略),发现只要贪心地取两端字典序较小的一端,所以在一开始对所有的正反后缀排序,即把原串倒过来接在后面求一遍SA就行了. 写了个倍增求SA[]+height[]的板子,代码可能比较长,但相对来说可能容易理解一点... #include <bits/stdc++.h>…
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2865 唯一出现的子串就是每个后缀除去和别的后缀最长的 LCP 之外的前缀: 所以用这个更新一段区间的答案,可以用线段树维护: 在 sa[i] ~ sa[i]+LCP+1 位置的答案由 LCP+1 更新,sa[i]+LCP+1 之后的位置就更新一个位置 ps 表示从 ps 到本位置的子串也可以: 最后两个取min即可: 注意如果整个后缀就是 LCP,那么就不能更新了: 线段树中 ps 的初值…
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3230 先算出每个后缀贡献子串的区间: 然后前缀LCP直接查询,后缀LCP二分长度,查询即可: 注意本质不同的子串的个数是 long long 级别!! 于是读入有 long long —— 快读也要写成 long long 的!!! 代码如下: #include<iostream> #include<cstdio> #include<cstring> #inclu…
3238: [Ahoi2013]差异 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 2326  Solved: 1054[Submit][Status][Discuss] Description Input 一行,一个字符串S Output 一行,一个整数,表示所求值 Sample Input cacao Sample Output 54 HINT 2<=N<=500000,S由小写英文字母组成 集训的时候想出来了还讲了一下 bingo! 前面…