cf244D. Match & 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 131313 etc..
    unsigned int hash = 0;  

    while (*str)
    {
        hash = hash * seed + (*str++);
    }  

    return (hash & 0x7FFFFFFF);
}  

本题hash解法 n^2

#define ULL unsigned long long
const int maxn = 5111 * 2;

const int HASH = 10007;
struct HashMap{
    int head[HASH];

    int next[maxn];
    ULL state[maxn];
    int num_s1[maxn];
    int num_s2[maxn];

    int sz;
    void init()
    {
        sz = 0;
        memset(head, -1, sizeof(head));
    }
    int insert(ULL val, bool info)
    {
        int h = val % HASH;
        for (int i = head[h]; i != -1; i = next[i])
        {
            if (val == state[i])
            {
                if (info) num_s1[i]++;
                else num_s2[i]++;
                return 1;///存在
            }
        }
        num_s1[sz] = 0;
        num_s2[sz] = 0;
        state[sz] = val;
        next[sz] = head[h];

        if (info) num_s1[sz]++;
        else num_s2[sz]++;

        head[h] = sz++;

        return 0;///不存在
    }
    bool check()
    {
        for (int i = 0; i < sz; i++)
        {
            if (num_s1[i] == num_s2[i] && num_s1[i] == 1)
                return true;
        }
        return false;
    }
}H;

const int SEED = 13331;
ULL P[maxn];
ULL s1[maxn], s2[maxn];

char sa[maxn], sb[maxn];

void hash_pre(ULL P[])
{
    P[0] = 1;
    for (int i = 1; i <= maxn; i++)
    P[i] = P[i - 1] * SEED;
}
void hash_init(ULL s1[], char sa[])///sa[],下标从0开始;对应是s1[]的值得下标从1开始
{
    int n = strlen(sa);
    s1[0] = 0;
    for (int i = 1; i <= n; i++)
        s1[i] = s1[i - 1] * SEED + sa[i - 1];
}
ULL getSeg(ULL s1[], int l, int r)///求s1[]的下标区间的hash值
{
    return s1[r] - s1[l - 1] * P[r - l + 1];
}

int main()
{
    hash_pre(P);

    RS(sa); RS(sb);
    int n = strlen(sa), m = strlen(sb);

    hash_init(s1, sa);
    hash_init(s2, sb);

    int fla = 0;
    int mn = min(n, m);
    for (int i = 1; i <= mn; i++)
    {
        H.init();
        for (int j = i; j <= n; j++)
        {
            H.insert(getSeg(s1, j - i + 1, j), 0);
        }
        for (int j = i; j <= m; j++)
        {
            H.insert(getSeg(s2, j - i + 1, j), 1);
        }

        if (H.check())
        {
            printf("%d\n", i);
            fla = 1;
            break;
        }
    }
    if (!fla) puts("-1");
    return 0;
}

后缀数组:

const int MAXN = 5111 * 2;
const int INF = 0x3f3f3f3f;
int wa[MAXN], wb[MAXN], wv[MAXN], wn[MAXN];
//char r[MAXN];
int a[MAXN], sa[MAXN], rank[MAXN], height[MAXN];

int cmp(int *r, int a,int b, int k)
{
    return r[a] == r[b] && r[a + k] == r[b + k];
}
void build_sa(int *r, int *sa, int n,int m)
{
   int i,j, p;
   int *x = wa, *y = wb, *t;
   for (int i= 0; i < m; i++) wn[i] = 0;
   for (int i= 0; i < n; i++) wn[x[i] = r[i]]++;
   for (int i = 1; i < m; i++) wn[i] += wn[i - 1];
   for (int i = n - 1; i >= 0; i--) sa[--wn[x[i]]] = i;
   for (p = 1, j = 1; p < n; j <<= 1, 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 < m; i++) wn[i] = 0;
       for (i = 0; i < n; i++) wn[wv[i] = x[y[i]]]++;
       for (i = 1; i < m; i++) wn[i] += wn[i - 1];
       for (i = n - 1; i >= 0; i--) sa[--wn[wv[i]]] = y[i];

       t = x; x = y; y = t;
       x[sa[0]] = 0; p = 1;
       for (i = 1; i < n; i++)
            x[sa[i]] = cmp(y, sa[i - 1], sa[i], j) ? p - 1 : p++;
   }
}
void getHeight(int *r, int *sa, int n)
{
    int i, j, k = 0;
    for (i = 1; i <= n; i++)
    {
        rank[sa[i]] = i;
        height[i] = 0;
    }
    for (i = 0;i < n; i++)
    {
        if (k) k--;
        j = sa[rank[i] - 1];
        while (r[i + k] == r[j + k]) k++;
        height[rank[i]] = k;
    }
}

char ca[MAXN], cb[MAXN];

void solve(int n)
{
    height[n + 1] = 0;
    int ans = INF;
    int l = strlen(ca);
    for (int i = 1; i <= n; i++)
    {
        if (!height[i]) continue;
        if (sa[i] < l && sa[i - 1] < l) continue;
        if (sa[i] >= l && sa[i - 1] >= l) continue;
        int pre = height[i - 1] + 1;
        int next = height[i + 1] + 1;
        if (height[i] >= max(pre, next))
        {
            ans = min(ans, max(pre, next));
        }
    }
    if (ans == INF) puts("-1");
    else printf("%d\n", ans);
}
int main()
{
    int t, n, m;

    ///n, m
    n = 0;
    m = 256;

    RS(ca);
    int l = strlen(ca);
    REP(j, l) a[n++] = (int)ca[j];
    a[n++] = m++;

    RS(cb);
    l = strlen(cb);
    REP(j, l) a[n++] = (int)cb[j];
    a[n++] = m++;

    a[--n] = 0; --m;

    build_sa(a, sa, n + 1, m);
    getHeight(a, sa, n);

    solve(n);

    return 0;
}
/*
0 8 0
1 6 0
2 4 2
3 2 4
4 0 6
5 7 0
6 5 1
7 3 3
8 1 5
^^^^^^^^^^^^^^

0 4
1 8
2 3
3 7
4 2
5 6
6 1
7 5
8 0
^^^^^^^^^^^^^^
*/

cf244D. Match & Catch 字符串hash (模板)或 后缀数组。。。,布布扣,bubuko.com

时间: 2024-10-11 14:23:50

cf244D. Match & Catch 字符串hash (模板)或 后缀数组。。。的相关文章

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

字符串HASH模板 取自挑战程序设计竞赛(第2版)

/*===================================================* 从b串中寻找和a串长度相同的子串,返回开始位置 不保证绝对正确,发生冲突概率为O(sqrt(n)), n为哈希函数的最大值 \*===================================================*/ #define ull unsigned long long const ull B = 1e8+7; /*according to the book*/

acdream1116 Gao the string!(hash二分 or 后缀数组)

问题套了一个斐波那契数,归根结底就是要求对于所有后缀s[i...n-1],所有前缀在其中出现的总次数.我一开始做的时候想了好久,后来看了别人的解法才恍然大悟.对于一个后缀来说 s[i...n-1]来说,所有与它匹配的前缀必然是和 s[i+1...n-1]  s[i+2...n-1] ....s[n-1..n-1]里的前缀匹配的,因而如果我们定义一个num[i]表示的是后缀s[i...n-1]与前缀的总长公共前缀,那么num[i]+num[i+1]+..num[n-1]就是前缀在后缀i里出现的次数

字符串Hash模板

1 unsigned int SDBMHash(char *str) { 2 unsigned int hash = 0; 3 while (*str) 4 // equivalent to: hash = 65599*hash + (*str++); 5 hash = (*str++) + (hash << 6) + (hash << 16) - hash; 6 7 return (hash & 0x7FFFFFFF); 8 } 9 10 // RS Hash Funct

字符串(马拉车算法,后缀数组,稀疏表):BZOJ 3676 [Apio2014]回文串

Description 考虑一个只包含小写拉丁字母的字符串s.我们定义s的一个子串t的“出 现值”为t在s中的出现次数乘以t的长度.请你求出s的所有回文子串中的最 大出现值. Input 输入只有一行,为一个只包含小写字母(a -z)的非空字符串s. Output 输出一个整数,为逝查回文子串的最大出现值. Sample Input [样例输入l] abacaba [样例输入2] www Sample Output [样例输出l] 7 [样例输出2] 4 HINT 一个串是回文的,当且仅当它从左

【模板】后缀数组

#include <cstdio> #include <iostream> #include <cstring> #define LL long long #define ULL unsigned long long using namespace std; const int MAXN=100010; //以下为倍增算法求后缀数组 int wa[MAXN],wb[MAXN],wv[MAXN],Ws[MAXN]; int cmp(int *r,int a,int b,i

poj 3461 字符串单串匹配--KMP或者字符串HASH

http://poj.org/problem?id=3461 先来一发KMP算法: #include <cstdio> #include <cstring> #include <algorithm> #include <string> #include <iostream> #include <cmath> #include <map> #include <queue> using namespace std;

LA 4513 Stammering Aliens 字符串hash

字符串hash模板, 本题是求,给定字符串s中至少出现m次的最长字符串长度,及此时起始位置的最大值 LA 4513  Stammering Aliens 白书p225 //#pragma warning (disable: 4786) //#pragma comment (linker, "/STACK:16777216") //HEAD #include <cstdio> #include <ctime> #include <cstdlib> #i

hdu4821 String 字符串hash(bkdrhash)

题意:给定m,l,一个字符串str. 我们定义一个子串为"recoverable"串 当 1.长度为 M*L 2.把这个好串分成M段,每段长度为L,且每段各不相同. 求"recoverable"串的个数,串相同位置不同也算不同. 思路:预处理数组hash,hash[i]表示从i位置到尾的字符串hash值.这里数组为unsigned long long型,因为可以自动取模.然后枚举 前l个位置,每次向后翻滚(将前一个长度为l的段hash值从map中去除,将翻滚后新出现