CF(427D-Match & Catch)后缀数组应用

题意:给两个字符串,求一个最短的子串。使得这个子串在两个字符串中出现的次数都等于1.出现的定义为:能够重叠的出现。

解法:后缀数组的应用。从小枚举长度。假设一个长度len合法的话:则一定存在这个样的sa[i]排名。sa[i]与s[i+1]的公共前缀长度大于等于len,且sa[i]与[i-1]的公共前缀长度小于len,同一时候sa[i+1]与[i+2]的公共前缀长度小于len,同一时候保证sa[i]与sa[i+1]在两个串中。Judge函数就是技巧性地实现了这些推断。

代码:

#include<iostream>
#include<string>
#include <cstring>
#include <string.h>
#include <stdio.h>
using namespace std;
const int MAX = 200100;

int n, num[MAX];
int sa[MAX], Rank[MAX], height[MAX];//sa[i]表示排名第i的后缀的位置,height[i]表示后缀SA[i]和SA[i-1]的最长公共前缀
int wa[MAX], wb[MAX], wv[MAX], wd[MAX];//名次数组 Rank[i] 保存的是 Suffix(i) 在全部后缀中从小到大排列的 “ 名次 ” 。
//简单的说,后缀数组(SA)是 “ 排第几的是谁? ” ,名次数组(RANK)是 “ 你排第几? ” 。 easy看出,后缀数组和名次数组为互逆运算。

int cmp(int *r, int a, int b, int l)
{
    return r[a] == r[b] && r[a+l] == r[b+l];
}

void da(int *r, int n, int m)            //  倍增算法0(nlgn)。
{
    int i, j, p, *x = wa, *y = wb, *t;
    for(i = 0; i < m; i ++) wd[i] = 0;
    for(i = 0; i < n; i ++) wd[x[i]=r[i]] ++;
    for(i = 1; i < m; i ++) wd[i] += wd[i-1];
    for(i = n-1; i >= 0; i --) sa[-- wd[x[i]]] = i;
    for(j = 1, p = 1; p < n; j *= 2, m = p)
    {
        for(p = 0, i = n-j; i < n; i ++) y[p ++] = i;
        for(i = 0; i < n; i ++) if(sa[i] >= j) y[p ++] = sa[i] - j;
        for(i = 0; i < n; i ++) wv[i] = x[y[i]];
        for(i = 0; i < m; i ++) wd[i] = 0;
        for(i = 0; i < n; i ++) wd[wv[i]] ++;
        for(i = 1; i < m; i ++) wd[i] += wd[i-1];
        for(i = n-1; i >= 0; i --) sa[-- wd[wv[i]]] = y[i];
        for(t = x, x = y, y = t, p = 1, x[sa[0]] = 0, i = 1; i < n; i ++)
        {
            x[sa[i]] = cmp(y, sa[i-1], sa[i], j) ? p - 1: p ++;
        }
    }
}

void calHeight(int *r, int n)            //  求height数组。
{
    int i, j, k = 0;
    for(i = 0; i < n; i ++) Rank[sa[i]] = i;
    for(i = 0; i < n; height[Rank[i ++]] = k)
    {
        for(k ? k -- : 0, j = sa[Rank[i]-1]; r[i+k] == r[j+k]; k ++);
    }
}

int len1=0;
int len2=0;
char s1[10000];
char s2[10000];
bool Judge(int n,int k)
{
    int a = 0,b = 0;
    for(int i = 0;i < n;i++)
    {
        if(height[i] < k)
        {
            if(a == 1 && b == 1)    return 1;
            a = b = 0;
        }
        if(sa[i] >= 0 && sa[i] < len1)  a++;
        if(sa[i] > len1 && sa[i] < n-1) b++;
    }
    return 0;
}
int main()
{
    scanf("%s%s",s1,s2);
    len1=strlen(s1);
    len2=strlen(s2);
    for(int i=0; i<len1; i++)
        num[i]=s1[i]-‘a‘+1;
    num[len1]=28;
    for(int i=0; i<len2; i++)
        num[i+len1+1]=s2[i]-‘a‘+1;

    da(num,len1+len2+2,30);
    calHeight(num,len1+len2+2);

    int len=min(len1,len2);
    int ans=-1;
    for(int i=1; i<=len; i++)
    {
        if(Judge(len1+len2+2,i))
        {
            ans=i;
            break;
        }
    }
    cout<<ans<<endl;
    return 0;
}
//20 5 19 20 19 5 20 19 5 19 28 20 5 5 16 20 5 19 0 0 0
时间: 2024-08-19 07:01:13

CF(427D-Match &amp; Catch)后缀数组应用的相关文章

CF 427D Match &amp; Catch 求最短唯一连续LCS

题目来源:CF 427D Match & Catch 题意:给出2个字符串 求最短的连续的公共字符串 并且该字符串在原串中只出现一次 思路:把2个字符串合并起来求height 后缀数组height的应用 #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn = 100010; char s[maxn]; int sa[maxn];

CF(427D-Match &amp; Catch)后缀数组应用

题意:给两个字符串,求一个最短的子串.使得这个子串在两个字符串中出现的次数都等于1.出现的定义为:可以重叠的出现. 解法:后缀数组的应用.从小枚举长度.如果一个长度len合法的话:则一定存在这个样的sa[i]排名.sa[i]与s[i+1]的公共前缀长度大于等于len,且sa[i]与[i-1]的公共前缀长度小于len,同时sa[i+1]与[i+2]的公共前缀长度小于len,同时保证sa[i]与sa[i+1]在两个串中.Judge函数就是技巧性地实现了这些判断. 代码: #include<iostr

D. Match &amp; Catch 后缀数组

Police headquarter is monitoring signal on different frequency levels. They have got two suspiciously encoded strings s1 and s2 from two different frequencies as signals. They are suspecting that these two strings are from two different criminals and

Codeforces Round #244 (Div. 2) D. Match &amp; Catch 后缀数组

链接: http://codeforces.com/contest/427/problem/D 题意: 给你两个字符串s1,s2,找出最短的子串出现在s1和s2中有且只有一次 题解: 还是把s1和s2连起来,求lcp.首先要知道得是,最短长度一定是sa数组中一定是相连的, 这样就只需要遍历一遍lcp数组,更新ans就可以了 ans = min(ans, max(lcp[i - 1], lcp[i + 1]) + 1) 代码: 31 int n, k; 32 int Rank[MAXN], tmp

Codeforces 427D Match &amp;amp; Catch(后缀自动机)

[题目链接] http://codeforces.com/problemset/problem/427/D [题目大意] 给出一个两个字符串,求出最短且在两个字符串中唯一的公共子串. [题解] 以原字符串的两倍建立自动机,按字典序在parent树上搜索, 得到的第一个长度为n的字符串就是答案. [代码] #include <cstdio> #include <cstring> #include <algorithm> #include <vector> us

codeforces 427D Match &amp; Catch(后缀数组,字符串)

题目 参考:http://blog.csdn.net/xiefubao/article/details/24934617 题意:给两个字符串,求一个最短的子串.使得这个子串在两个字符串中出现的次数都等于1.出现的定义为:可以重叠的出现. 解法:后缀数组的应用.从小枚举长度.如果一个长度len合法的话:则一定存在这个样的sa[i]排名.sa[i]与s[i+1]的公共前缀长度大于等于len,且sa[i]与[i-1]的公共前缀长度小于len,同时sa[i+1]与[i+2]的公共前缀长度小于len,同时

cf244D. Match &amp; Catch 字符串hash (模板)或 后缀数组。。。

D. Match & Catch 可以用各种方法做,字符串hash,后缀数组,dp,拓展kmp,字典树... 字符串hash(模板) http://blog.csdn.net/gdujian0119/article/details/6777239 BKDR Hash Function : // BKDR Hash Function unsigned int BKDRHash(char *str) { unsigned int seed = 131; // 31 131 1313 13131 13

cf244D. Match &amp;amp; Catch 字符串hash (模板)或 后缀数组。。。

D. Match & Catch 能够用各种方法做.字符串hash.后缀数组,dp.拓展kmp,字典树.. . 字符串hash(模板) http://blog.csdn.net/gdujian0119/article/details/6777239 BKDR Hash Function : // BKDR Hash Function unsigned int BKDRHash(char *str) { unsigned int seed = 131; // 31 131 1313 13131 1

CF 427D 后缀数组

大意是寻找两个字符串中最短的公共子串,要求子串在两个串中都是唯一的. 造一个S#T的串,做后缀数组,从小到大枚举子串长度在height数组中扫描,如果某一个组中来自两个串的数量分别为1,就找到了答案. 1 #include <iostream> 2 #include <vector> 3 #include <algorithm> 4 #include <string> 5 #include <string.h> 6 #include <st