![](https://img-blog.csdnimg.cn/20201014180756754.png?x-oss-process=image/resize,m_fixed,h_64,w_64)
字符串
图一乐图一乐
这个作者很懒,什么都没留下…
展开
-
E. Martian Strings(kmp前后缀拼接)
给出一个文本串s,100个模式串,每个模式串长度不超过1000,求有几个满足存在a<=b<c=da<=b<c=da<=b<c=d,使得s[a..b]+s[c..d]=ts[a..b]+s[c..d]=ts[a..b]+s[c..d]=t,先求一遍模式串前缀最左出现位置,存起来,再倒着来一遍,求后缀最优出现位置,不能判断时看看是否相交。const int N = 1e5 + 5;int nxt[N];char s[N], ins[N];char tmp[1005],原创 2020-10-29 14:05:23 · 135 阅读 · 0 评论 -
P1117 [NOI2016]优秀的拆分(后缀数数 or hash+差分)
思路:直接上后缀数组可以通过求lcp把本来的问题从N3N^3N3降到N2N^2N2,但是这样还是有4.5e8的复杂度,只能95分。再次考虑优化。假设在枚举AABB中A的长度len时,考虑对字符串按照len进行分块,例如len=2,把s=“abababab”,分成s=“ab ab ab ab”,这样len为2的A顶多出现在两个块中,然后考虑前后拼接,维护一个正向的后缀数组,一个反向的后缀数组,这样在枚举每一段时就可以知道然后就在每次枚举相邻的两个块,求lcp,lcs,差分记录对区间的贡献。总结:多造样例,原创 2020-10-27 15:04:30 · 189 阅读 · 0 评论 -
P1972 [SDOI2009]HH的项链(区间不同颜色数量)
const int N = 1e6 + 5;int tree[N],n;void add(int k, int num){ for (int i = k;i <= n;i += i & -i) tree[i] += num;}int read(int k){ int sum = 0; for (int i = k;i > 0;i -= i & -i) sum += tree[i]; return sum;}struct node{ int l,原创 2020-10-13 11:56:29 · 133 阅读 · 0 评论 -
P4248 [AHOI2013]差异(单调栈,后缀数组height[])
设lcp(i,j)=min(height[i],height[j])=height[k]lcp(i,j)=min(height[i],height[j])=height[k]lcp(i,j)=min(height[i],height[j])=height[k]问题转化为了求每个height[k]的贡献:即height[k]在多大的区间内是最小的,单调一下就好了。const int N = 5e5+10, M = 30;char s[N];int sa[N], t[N << 1], t2[原创 2020-09-11 11:22:00 · 102 阅读 · 0 评论 -
F - Forbidden Indices(后缀数组或后缀自动机)
后缀数组思路:先把字符串倒一下,不能以某点结尾就变成了不能以某点开头,假设现在没有限制,求max(∣a∣f(a))max(|a|f(a))max(∣a∣f(a)),可以考虑height[]height[]height[]所展示的直方图,枚举枚举heigtht[i]heigtht[i]heigtht[i],找到直方图中左右一个小于当前heigtht[i]heigtht[i]heigtht[i]的位置分别记为L[i],R[i]L[i],R[i]L[i],R[i],这时的答案就是max(height[i]∗(R[原创 2020-09-08 20:35:29 · 224 阅读 · 2 评论 -
P4070 [SDOI2016]生成魔咒(SAM板子题,求本质不同子串)
思路:每个加入一个字符,它对总体本质不同子串的贡献就是maxlen[now]−maxlen[link[now]]maxlen[now]-maxlen[link[now]]maxlen[now]−maxlen[link[now]],还有就是这里的儿子范围分散,转移数组用map。ll ans;struct Suffix_Automata {//minlen[i]=maxlen[link[i]]+1; int maxlen[N << 1], link[N << 1], A[N <原创 2020-09-08 19:53:41 · 212 阅读 · 0 评论 -
Problem M – Marblecoin(后缀数组,贪心)
首先:不得不说,后缀数组,永远滴神!题意:有n个栈,每次可以从栈顶取一个元素,获得价值为v*365t^tt,其中v是这个元素的价值,是这个元素将拥有的天数,求最小总价值。思路:这是个可以用贪心可以解决的问题,越早拿,系数越高,应该拿的元素的v也应该小,然而当两个数相同,就无法判断该从哪个栈中取。仔细想不难发现,这个问题的本质就是每次从字典序小的栈中拿出一个元素。然后就可以用后缀数组做了,两个栈之间用一个大的数隔开,每次取出后缀排名最高(rank最小的)的栈的栈顶。收获:学到了维护多个串字典序关系的算法原创 2020-09-07 12:06:42 · 184 阅读 · 0 评论 -
P3763 [TJOI2017]DNA(后缀数组,ST表)
思路:通过学习后缀数组知识了解,第i大的后缀和第j大的后缀的lcp等于它们之间,所有相邻对的lcp的最小值。然后题意是最多可以skip3个不同的点,求sss中有多少子串和s0s_0s0匹配。const int N = 2e5+5, M = 21;char s[N],s0[N];int sa[N], t[N << 1], t2[N << 1], c[N], height[N], rk[N];int n, m;void get_sa(){ //s从1开始,排名从1开始原创 2020-09-03 22:54:46 · 121 阅读 · 0 评论 -
AcWing 1052. 设计密码(状态机+kmp)
const int N = 55, M = 105;char s[N];int nxt[N], f[N][N];void kmp_pre(char s[], int n){ int j = 0; nxt[0] = -1, nxt[1] = 0; for (int i = 2; i <= n; i++) { while (j && s[i] != s[j + 1]) j = nxt[j]; if (s[j + 1] == s[i]) j++; nx原创 2020-09-02 16:08:52 · 182 阅读 · 0 评论 -
H - Queries for Number of Palindromes(dp,记忆化搜索,hash)
思路:设f[l][r]f[l][r]f[l][r]表示求解的范围,可以想到递归方程:f[l][r]=f[l+1][r]+f[l][r−1]−f[l+1][r−1]+vis[l][r]f[l][r]=f[l+1][r]+f[l][r-1]-f[l+1][r-1]+vis[l][r]f[l][r]=f[l+1][r]+f[l][r−1]−f[l+1][r−1]+vis[l][r],其中vis[l][r]vis[l][r]vis[l][r]表示这段是否是回文,这里可以暴力N*N求,当然如果N更大,考虑hash预处原创 2020-09-01 22:43:18 · 146 阅读 · 0 评论 -
D - Palindromic characteristics(Manacher+记忆化搜索)
题意:定义k_Palindromic为某个字符串的回文系数,给一个字符串,统计它的所有子串的回文系数。思路:这里N=5E3,暗示N*N的做法也可以,子串理解为所有前缀的后缀,然后枚举每个前缀,记忆化搜索中先判断当前是不是回文,是的话再递归求解,递归的过程中的所有解都是之前算过的,所以记忆化一下。const int N = 5e3 + 5;char Ma[N << 1], s[N];int r[N << 1];void Manacher(char s[], int len)原创 2020-09-01 18:00:08 · 122 阅读 · 0 评论 -
J - Non Super Boring Substring(Manacher+树状数组)
题意:求字符串s中good的子串的数量,一个子串是good的如果它不包含长度大于等于k的回文串。思路:每个子串可以理解为每个前缀的每个后缀,利用Mancher算法算出长度大于等于k的回文,然后就树状数组区间搞一下每个回文对后面哪些位置有贡献,这里奇偶回文以及k的奇偶需要细致讨论。const int N = 1e5 + 5;char Ma[N << 1], s[N];int r[N << 1];int tree[N], n, k;void add(int k, int nu原创 2020-09-01 11:17:17 · 117 阅读 · 0 评论 -
M - Mediocre String Problem(Manacher算法+hash二分求lcp)
思路:由题意可知,回文的中心一定在s所取的部分中,然后可以想到s[i...k]s[i...k]s[i...k]必定和t[1...k]t[1...k]t[1...k]是lcp(s中是倒着匹配),并且s[k+1...j]s[k+1...j]s[k+1...j]也需要是回文。所以可以枚举s中每个点为断点,用hash和二分求出lcp,并在Manacher算法中预处理出每个断点右边相邻的回文串的个数。char s[N<<1], t[N];int lens, lent;ll p1[N], p2[N],原创 2020-08-31 20:43:38 · 227 阅读 · 0 评论 -
P3649 [APIO2014]回文串(回文自动机板子题)
const int N = 3e5 + 5;struct PAM {#define KIND 26 int n, last, tot; int len[N], trie[N][KIND], fail[N], cnt[N], S[N], num[N]; //len[i]: 节点i所代表的回文串长度, fail[i]: 当前回文串的最长回文后缀(不包括自身) //cnt[i]: 节点i所代表的回文串的个数, S[i]: 第i次添加的字符, num[i]: 以第i个字符为结尾的回文串个数 //la原创 2020-08-28 21:46:55 · 132 阅读 · 0 评论 -
P1659 [国家集训队]拉拉队排练(回文自动机板子题)
const int N = 1e6 + 5;struct PAM {//主要可以解决以下问题//1.本质不同回文串个数//2.每个本质不同回文串出现的次数//3.以某一个节点为结尾的回文串个数#define KIND 26 int n, last, tot; int len[N], trie[N][KIND], fail[N], S[N], num[N]; ll cnt[N]; //len[i]: 节点i所代表的回文串长度, fail[i]: 当前回文串的最长回文后缀(不包括自身)原创 2020-08-28 21:04:09 · 220 阅读 · 0 评论 -
P4555 [国家集训队]最长双回文串(Manacher,枚举分割点)
char Ma[N<<1],s[N];int r[N<<1];int L[N << 1], R[N << 1];void Manacher(char s[], int len){ int l = 0; Ma[l++] = '$'; Ma[l++] = '#'; for (int i = 0;i < len;i++) { Ma[l++] = s[i]; Ma[l++] = '#'; } Ma[l] = 0; int mx =原创 2020-08-28 15:56:28 · 85 阅读 · 0 评论 -
P2375 [NOI2014]动物园(kmp)
const int N = 1e6 + 5;int nxt[N];char s[N], t[N];int num[N];void kmp_pre(char s[], int n) { nxt[0]=-1,nxt[1] = 0; num[1] = 1; for(int i = 2,j=0; i <= n; i ++) { while(j && s[i] != s[j + 1]) j = nxt[j]; if(s[j + 1] == s[i])j ++;原创 2020-08-27 15:03:16 · 143 阅读 · 0 评论