uva 10829 - L-Gap Substrings(后缀数组)

题目链接:uva 10829 - L-Gap Substrings

题目大意:给定一个字符串,问有多少字符串满足UVU的形式,要求U非空,V的长度为g。

解题思路;对字符串的正序和逆序构建后缀数组,然后枚举U的长度l,每次以长度l分区间,在l和l+d+g所在的两个区间上确定U的最大长度。

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>

using namespace std;

typedef long long ll;
const int maxn = 100005;

struct Suffix_Arr {
    int n, len, s[maxn];
    int SA[maxn], rank[maxn], height[maxn];
    int tmp_one[maxn], tmp_two[maxn], c[30];

    int d[maxn][20];

    void init(char* str);
    void build_arr(int m);
    void get_height();

    void rmq_init();
    int rmq_query(int l, int r);
    ll solve(int m);

    void put();
}AC;

char str[maxn];

int main () {
    int cas, n;
    scanf("%d", &cas);
    for (int i = 1; i <= cas; i++) {
        scanf("%d%s", &n, str);
        AC.init(str);
        printf("Case %d: %lld\n", i, AC.solve(n));
    }
    return 0;
}

void Suffix_Arr::put () {
    for (int i = 0; i < n; i++)
        printf("%d ", SA[i]);
    printf("\n");

    for (int i = 0; i < n; i++)
        printf("%d ", height[i]);
    printf("\n");
}

ll Suffix_Arr::solve(int m) {
    build_arr(28);
    get_height();

    rmq_init();

    ll ret = 0;
    for (int l = 1; l < len / 2; l++) {
        for (int i = 0; i < len; i += l) {
            int j = i + l + m, sum = 0;

            if (j < len)
                sum += min(rmq_query(rank[i], rank[j]), l);
            if (i)
                sum += min(rmq_query(rank[n-i-1], rank[n-j-1]), l-1);
            ret += max(0, sum - l + 1);
        }
    }
    return ret;
}

int Suffix_Arr::rmq_query(int l, int r) {

    if (l > r) swap(l, r);
    l++;

    int k = 0;
    while ((1<<(k+1)) <= r - l + 1) k++;
    return min(d[l][k], d[r - (1<<k) + 1][k]);
}

void Suffix_Arr::rmq_init() {
    for (int i = 0; i < n; i++) d[i][0] = height[i];

    for (int k = 1; (1<<k) <= n; k++) {
        for (int i = 0; i + (1<<k) - 1 < n; i++)
            d[i][k] = min(d[i][k-1], d[i+(1<<(k-1))][k-1]);
    }
}

void Suffix_Arr::init(char* str) {
    n = 0;
    len = strlen(str);
    for (int i = 0; i < len; i++)
        s[n++] = str[i] - ‘a‘ + 1;
    s[n++] = 27;
    for (int i = len - 1; i >= 0; i--)
        s[n++] = str[i] - ‘a‘ + 1;
    s[n++] = 0;
}

void Suffix_Arr::get_height() {
    for (int i = 0; i < n; i++)
        rank[SA[i]] = i;

    int mv = height[0] = 0;
    for (int i = 0; i < n - 1; i++) {
        if (mv) mv--;

        int j = SA[rank[i] - 1];
        while (s[i+mv] == s[j+mv])
            mv++;
        height[rank[i]] = mv;
    }
}

void Suffix_Arr::build_arr(int m) {
    int *x = tmp_one, *y = tmp_two;

    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 mv = 0;
        for (int i = n - k; i < n; i++) y[mv++] = i;
        for (int i = 0; i < n; i++) if (SA[i] >= k)
            y[mv++] = 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 = 1; 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);
        mv = 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] ? mv - 1 : mv++);

        if (mv >= n)
            break;
        m = mv;
    }
}
时间: 2024-10-19 04:11:25

uva 10829 - L-Gap Substrings(后缀数组)的相关文章

POJ 1226 Substrings (后缀数组)

题目大意: 问的是m个字符串里,都出现过的子串.子串也可以出现在这个串的逆序串中. 思路分析: 居然wa在全5个 "a" 的数据上. 二分的时候下界不能为0.. 思路大致上是把原串和逆序串全部处理出来,放入str中,然后在每个串中间加一个没有出现过的. 此处注意输入不仅仅是字母. 然后跑一遍后缀数组. 然后用标记计数就好了. #include <iostream> #include <cstdio> #include <algorithm> #inc

uva 261 - The Window Property(后缀数组)

题目链接:uva 261 - The Window Property 题目大意:给定给一个字符串,枚举子串长度k(len≥k≥1),要求在任意k时,有不超过k+1个不同的子串,如果有的话则输出NO,并且输出最早发现不满足的位置. 解题思路:后缀数组,处理出height数组,对于每个k,遍历height数组,碰到小于k的则分段,将整个height分成若干段,即为有多少种长度为k的不同前缀,需要注意的是要跳过前缀长度不足k的. #include <cstdio> #include <cstr

UVA 题目1223 - Editor(后缀数组求出现次数超过两次的最长子串的长度)

Mr. Kim is a professional programmer. Recently he wants to design a new editor which has as many functions as possible. Most editors support a simple search function that finds one occurrence (or all occurrences successively) of a query pattern strin

POJ 3415 Common Substrings 后缀数组+并查集

后缀数组,看到网上很多题解都是单调栈,这里提供一个不是单调栈的做法, 首先将两个串 连接起来求height   求完之后按height值从大往小合并.  height值代表的是  sa[i]和sa[i-1] 的公共前缀长度,那么每次合并就是合并  i和i-1 那么在合并小的时候公共前缀更大的肯定已经都合并在一起,那么就可以直接统计了. #include<iostream> #include<cstdio> #include<algorithm> #include<

spoj Distinct Substrings 后缀数组

给定一个字符串,求不相同的子串的个数. 假如给字符串“ABA";排列的子串可能: A B A AB  BA ABA 共3*(3+1)/2=6种; 后缀数组表示时: A ABA BA 对于A和AB height[i]=1; 表明一个长度公共,所以ABA中多出现了A这个子串,所以6-1=5: 对于ABA BA height[i]=0,所以不需要减去. 最后答案为5: #include<iostream> #include<stdio.h> #include<string

POJ1226:Substrings(后缀数组)

Description You are given a number of case-sensitive strings of alphabetic characters, find the largest string X, such that either X, or its inverse can be found as a substring of any of the given strings. Input The first line of the input contains a

poj Common Substrings(后缀数组&amp;单调队列)

Common Substrings Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 7082   Accepted: 2355 Description A substring of a string T is defined as: T(i, k)=TiTi+1...Ti+k-1, 1≤i≤i+k-1≤|T|. Given two strings A, B and one integer K, we define S, a

SPOJ 694 || 705 Distinct Substrings ( 后缀数组 &amp;&amp; 不同子串的个数 )

题意 : 对于给出的串,输出其不同长度的子串的种类数 分析 : 有一个事实就是每一个子串必定是某一个后缀的前缀,换句话说就是每一个后缀的的每一个前缀都代表着一个子串,那么如何在这么多子串or后缀的前缀中找出不同的并计数呢?思路就是所有的可能子串数 - 重复的子串数.首先我们容易得到一个长度为 len 的串的子串数为 len * ( len + 1) / 2.那如何知道重复的子串数呢?答案就是利用后缀数组去跑一遍 Height ,得到所有的最长公共前缀(LCP),这些最长公共前缀的值都存在了 He

POJ 3415 Common Substrings(后缀数组求重复字串)

题目大意:给你两个字符串,让你求出来两个字符串之间的重复子串长度大于k的有多少个. 解题思路: 先说论文上给的解释:基本思路是计算A的所有后缀和B的所有后缀之间的最长公共前缀的长度,把最长公共前缀长度不小于k的部分全部加起来.先将两个字符串连起来,中间用一个没有出现过的字符隔开.按height值分组后,接下来的工作便是快速的统计每组中后缀之间的最长公共前缀之和.扫描一遍,每遇到一个B的后缀就统计与前面的A的后缀能产生多少个长度不小于k的公共子串,这里A的后缀需要用一个单调的栈来高效的维护.然后对