bzoj3796

来源:互联网 发布:coc闪电劈防空数据 编辑:程序博客网 时间:2024/06/07 03:50

就是kmp+二分+后缀数组

后缀数组注意中间插一个没有出现的字母,然后从1开始,我是从0的导致常数大了一点点。

kmp的时候标记起点,然后注意从起点开始只有长度达到了strlen(s3)以上的才会包含s3

这题的感觉就是在后缀数组中有相同前缀的一定是紧挨在一起的。

还有注意一下二分技巧:

求最大值从(l+r)/2+1查找 求最小值从(l+r)/2-1查找,最大值最小序更新l,最大值最大序更新r,其他都差不多了。

貌似后缀自动机也阔以做,等我以后再补。。

#include<iostream>#include<cstdio>#include<algorithm>#include<string.h>using namespace std;char str1[200020], str3[20020];int buc[200020], rank1[200020], ran2pos[200020],sa[200020],lcp[200020],nextt[200020],num[200020];void getsa(char *s, int len){int m = len > 400 ? len : 400;for (int i = len; i <= 2 * len; i++)ran2pos[i] = -1, rank1[i] = -1;for (int i = 0; i < m; i++)buc[i] = 0;for (int i = 0; i < len; i++)buc[rank1[i] = s[i]]++;for (int i = 1; i < m; i++)buc[i] += buc[i - 1];for (int i = len - 1; i >= 0; i--)sa[--buc[rank1[i]]] = i;for (int k = 1; k <= len; k*=2){int p = 0;for (int i = len - 1; i >= len-k; i--)ran2pos[p++] = i;for (int i = 0; i < len; i++)if (sa[i]>k - 1)ran2pos[p++] = sa[i] - k;for (int i = 0; i < m; i++)buc[i] = 0;for (int i = 0; i < p; i++)buc[rank1[ran2pos[i]]]++;for (int i = 1; i < m; i++)buc[i] += buc[i - 1];for (int i = p - 1; i >= 0; i--)sa[--buc[rank1[ran2pos[i]]]] = ran2pos[i];swap(rank1, ran2pos);int r = 1; rank1[sa[0]] = 0;for (int i = 1; i < len; i++){if (ran2pos[sa[i]] == ran2pos[sa[i - 1]] && ran2pos[sa[i] + k] == ran2pos[sa[i - 1] + k])rank1[sa[i]] = r - 1;elserank1[sa[i]] = r++;}if (r>= len)break;m = r;}int h = 0;for (int i = 0; i < len; i++)rank1[sa[i]] = i;for (int i = 0; i < len; i++){if (rank1[i] == len - 1)continue;int now = sa[rank1[i] + 1];if (h > 0)h--;while (s[now + h] == s[i + h])h++;lcp[rank1[i]] = h;}}void getnext(char *s, int len){int now = -1; nextt[0] = -1;for (int i = 1; i < len; i++){while (now!=-1&&s[i] != s[now + 1])now = nextt[now];if (s[now + 1] == s[i])nextt[i] = now + 1; else nextt[i] = -1;now = nextt[i];}}void kmp(char *s, int lens,char* model,int lenm){int now = -1;for (int i = 0; i < lens; i++){while (now != -1 && s[i] != model[now + 1])now = nextt[now];if (s[i] == model[now + 1])now++;if (now == lenm - 1)num[i - lenm + 1]++;}for (int i = 1; i < lens; i++)num[i] += num[i - 1];}bool check(int len1,int lenth,int *lcp,int strlenth,int modellenth){for (int i = 0; i < strlenth-1; i++)//每个后缀对应一个级别,这里i枚举的是级别{if ((sa[i] > len1&&sa[i + 1] > len1) || (sa[i] <len1&&sa[i + 1] < len1))continue;int before, after;if (sa[i] > len1&&sa[i + 1] < len1)after = sa[i], before = sa[i + 1]; else after = sa[i + 1], before = sa[i];int templen = min(lcp[i], lenth);if (templen>= lenth)//这还要注意我们是两个串合在一起的{if (templen < modellenth)return true;int start = before; int end = before+templen-1;int newend = end - modellenth+1;//这里主要是看那段有没有model的起点如果有就不行,后面的位置就算是有model的起点也是不存在的。if (start-1>= 0){if (num[newend] - num[start - 1] == 0)return true;}elseif (num[newend] == 0)return true;}}return false;}int main(){//int k = 'A';//cout << k << endl;scanf("%s", str1);int len1 = strlen(str1);str1[len1] = 'a' - 1;len1++;scanf("%s" ,str1 + len1);int alllen = strlen(str1);scanf("%s", str3);int all3len = strlen(str3);getsa(str1, alllen);getnext(str3, all3len);kmp(str1, alllen, str3, all3len);int l = 0; int r = alllen;while (l < r){int mid = (l + r) / 2 + 1;//因为要求最大值所以先考虑大的。if (check(len1, mid, lcp, alllen, all3len))l = mid;elser = mid - 1;}printf("%d\n", l);}




原创粉丝点击