poj 2774 Long Long Message 后缀数组

来源:互联网 发布:淘宝网木质沙发 编辑:程序博客网 时间:2024/05/29 13:13
//poj 2774 Long Long Message 后缀数组////题目大意:////求两个串的最长公共子串.////解题思路:////后缀数组.将两个字符串用一个不出现在两个字符串的其他字符连接,并在最后//同样用一个字符作为结束.一个串的子串,一定是某个后缀的前缀.求出height数组//height[i]表示sa[i-1]和sa[i]的公共前缀LCP.这样将两个字符串接起来.最长公共//子串一定会是相邻的.如果不相邻,那肯定会有拥有与他更长的公共串的串与其相邻//因为他们是排在一起的.这一点是关键.最后只要求是否在两个不相同的串中取出一个//最大的height[i]就是所谓的答案.////感悟:////尽管看到了罗前辈的论文,知道整体的思想,学习了刘老师的倍增算法.按照自己的理解//敲了一下后缀数组,结果一直是RE,一直是WA,搜了搜题解.发现各位前辈大牛写的都是差不多//的.但是自己就是一直在wa.然后发现,自己并没有懂得后缀数组.不知道要在后面加上一个最小//的字符.(这是为了方便比较大小)我的理解就是这个字符定义下了一个标杆,由于比所有的都要小//更加有效的实现了倍增.两个关键字的排序结合了一个小的标号,不仅不影响结果,反而会更加有效//实现两两比较.这是我WA的第一个原因.第二个就是擅自将c的范围改到了500,变小了.其实这样是//有问题的.因为按照的是基数排序.最后的结果肯定是0~n-1范围的.所以c小了,肯定是会RE的.这是//所谓的基数排序.又一次加强了自己的理解.这道题从开始看,到最后的AC和理解.一共用了5个小时//期间,我一直各种debug.怀疑这里错了,怀疑那里错了.现在还是脑子一团浆糊.到不了真正能够应用的//层面,但我依然会坚持.没有人教,那么有的就是自学.有的是自己的脑子.在最困难,最焦虑的时候.冷静//清醒.千万不能慌,虽然这是一道后缀数组的裸题.但我在了解了做法的基础上,依然是花了5个小时才//AC.还是自己太笨了,也是倍增太神奇了.套模板,我还是永远不会.只能一遍一遍的理解.//总的来说,人生第一道后缀数组,虽然艰辛无数.但还是有那么一丝的收获.哪怕只是一点点,我也会//为之头破血流.更何况,才费点脑子的事儿,继续加油吧!FIGHTING!!!#include <cstdio>#include <iostream>#include <algorithm>#include <cstring>using namespace std;const int MAX_N = 500009;int n;int c[MAX_N];int sa[MAX_N];int height[MAX_N];int rank[MAX_N];int t[MAX_N];int t2[MAX_N];char str1[MAX_N];char str2[MAX_N];int u;int s[MAX_N];void build_sa(int n,int m){int *x = t;int *y = t2;for (int i=0;i<m;i++)c[i] = 0;for (int i=0;i<n;i++)c[x[i] = s[i]]++;for (int i=1;i<m;i++)c[i] += c[i-1];for (int i=n-1;i>=0;i--)sa[--c[x[i]]] = i;for (int k = 1 ;k <= n ;k <<=1){int p = 0;for (int i=n-k;i<n;i++)y[p++] = i;for (int i=0;i<n;i++)if (sa[i] >= k)y[p++] = sa[i] - k;for (int i = 0;i < m; i++)c[i] = 0;for (int i = 0;i < n; i++)  c[x[y[i]]]++;for (int i=0;i<m;i++)c[i] += c[i-1];for (int i=n-1;i>=0;i--)sa[--c[x[y[i]]]] = y[i];swap(x,y);p = 1;x[sa[0]] = 0;for (int i=1;i<n;i++)x[sa[i]] = y[sa[i-1]]==y[sa[i]] && y[sa[i-1]+k] == y[sa[i]+k]?p-1:p++;if (p>=n)break;m = p;}}void get_h(int n){for (int i = 0;i < n;i++)rank[sa[i]] = i;int k = 0;//int j;//height[0] = 0;for (int i = 0;i < n;i++){if (k) k--;int j = sa[rank[i]-1];while(s[i+k]==s[j+k])k++;height[rank[i]] = k;//cout << k << endl;}}bool judge(int i){if ((sa[i-1]<u && u < sa[i]) ||(sa[i] < u && u < sa[i-1]))return true;return false;}void print(int *a){for (int i=0;i<n;i++){printf("%d ",a[i]);}cout << endl;}int get_long(){int mx = 0;for (int i=1;i<n;i++){if (height[i]>mx && judge(i)){mx = height[i];}}return mx;}void solve(){int len1 = strlen(str1);int len2 = strlen(str2);u = len1;//str1[len++] = '#';//for (int i = 0;str2[i];i++,len++){//str1[len] = str2[i];//}//str1[len++] = 0;//n = len;n = 0;for (int i=0;str1[i];i++)s[n++] = str1[i] - 'a' + 1;s[n++] = 28;for (int i =0;str2[i];i++)s[n++] = str2[i] - 'a' + 1;//cout << n << " " << len1 + len2 << endl;s[n++] = 0;build_sa(n,30);//print(sa);//cout << str1 << endl;get_h(n);//print(height);printf("%d\n",get_long());}int main(){//freopen("1.txt","r",stdin);while(scanf("%s%s",str1,str2)!=EOF){solve();}return 0;}

0 0
原创粉丝点击