hdu-6194 string string string 后缀数组 出现恰好K次的串的数量

最少出现K次我们可以用Height数组的lcp来得出,而恰好出现K次,我们只要除去最少出现K+1次的lcp即可。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;

const int maxn = 100000 + 10;

int t1[maxn], t2[maxn], c[maxn];

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

void da(int str[], int sa[], int Rank[], int lcp[], int n, int m) {
    ++n;
    int i, j, p, *x = t1, *y = t2;
    for (i = 0; i < m; ++i) c[i] = 0;
    //        puts("hha");
    for (i = 0; i < n; ++i) c[x[i] = str[i]]++;
    for (i = 1; i < m; ++i) c[i] += c[i - 1];
    for (i = n - 1; i >= 0; --i) sa[--c[x[i]]] = i;
    for (j = 1; j <= n; j <<= 1) {
        p = 0;
        for (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) c[i] = 0;
        for (i = 0; i < n; ++i) c[x[y[i]]]++;

        for (i = 1; i < m; ++i) c[i] += c[i - 1];
        for (i = n - 1; i >= 0; --i) sa[--c[x[y[i]]]] = y[i];

        swap(x, y);
        p = 1; x[sa[0]] = 0;
        for (i = 1; i < n; ++i) {
            x[sa[i]] = cmp(y, sa[i - 1], sa[i], j) ? p - 1 : p++;
        }
        if (p >= n)break;
        m = p;
    }

    int k = 0;
    n--;
    for (i = 0; i <= n; ++i) Rank[sa[i]] = i;
    for (i = 0; i < n; ++i) {
        if (k)--k;
        j = sa[Rank[i] - 1];
        while (str[i + k] == str[j + k])++k;
        lcp[Rank[i]] = k;
        //cout << k << endl;
    }
}

int lcp[maxn], a[maxn], sa[maxn], Rank[maxn];

char s[maxn];

int d[maxn][40];
int len;

void rmq_init(int* A, int n) {
    for (int i = 0; i < n; ++i) d[i][0] = A[i];
    for (int j = 1; (1 << j) <= n; ++j)
        for (int i = 0; i + (1 << j) - 1 < n; ++i)
            d[i][j] = min(d[i][j - 1], d[i + (1 << (j - 1))][j - 1]);
}

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

int ask(int l, int r) {
    if (l == r) return len - sa[r]; /// l == r的话 是一个串, 返回本身的长度即可。
    return ASK(l + 1, r); ///否则在rmq查询。
}

//
int main() {
    //freopen("in.txt", "r", stdin);
    //freopen("outstd.txt", "w", stdout);
    int T;
    scanf("%d", &T);
    while (T--) {
        int k;
        scanf("%d", &k);
        scanf("%s", s);
        //puts(s);
        len = strlen(s);
        for (int i = 0; i < len; ++i) {
            a[i] = s[i] - ‘a‘ + 1;
        }
        a[len] = 0;
        da(a, sa, Rank, lcp, len, 30);
        rmq_init(lcp, len + 1);
        long long ans = 0;
        if (k == 1)
        {
            for (int i = 1; i <= len; i++)
            {
                int siz = len - sa[i];
                int des = 0;
                if (i > 1) des = max(des, ask(i - 1, i));
                if (i < len) des = max(des, ask(i, i + 1));
                ans += siz - des;
            }
        }
        else
        {
            for (int i = 1; i+k-1 <= len; i++)
            {
                int siz = ask(i, i + k - 1);
                int des = 0;
                if (i > 1) des = max(des, ask(i - 1, i + k - 1));
                if (i + k <= len) des = max(des, ask(i, i + k));
                ans += siz - des;
            }
        }
        printf("%I64d\n", ans);
        /*
        long long ans = 0;

        for (int i = 1; i + k - 1 <= len; ++i) {
            ans += ask(i, i + k - 1);
            if (i - 1 > 0)ans -= ask(i - 1, i + k - 1); ///注意边界问题。
            if (i + k <= len)ans -= ask(i, i + k);
            if (i - 1 > 0 && i + k <= len)ans += ask(i - 1, i + k);
        }
        printf("%I64d\n", ans);*/

    }
    return 0;
}
时间: 2024-08-25 17:13:51

hdu-6194 string string string 后缀数组 出现恰好K次的串的数量的相关文章

POJ 题目3294Life Forms(后缀数组求超过k个的串的最长公共子串)

Life Forms Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 11178   Accepted: 3085 Description You may have wondered why most extraterrestrial life forms resemble humans, differing by superficial traits such as height, colour, wrinkles, e

hdu 3518 Boring counting(后缀数组)

Boring counting                                                                       Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Problem Description 035 now faced a tough problem,his english teacher gives him

hdu 4691 Front compression (后缀数组)

题目大意: 介绍了一种压缩文本的方式,问压缩前后的文本长度. 思路分析: 后缀数组跑模板然后考虑两次l r之间的lcp. 然后减掉重复的长度. 注意ans2的累加. #include <cstdio> #include <iostream> #include <cstring> #include <algorithm> #include <cmath> #define maxn 200005 using namespace std; typede

URAL 1517 Freedom of Choice(后缀数组,最长公共字串)

题目 输出最长公共字串 #define maxn 200010 int wa[maxn],wb[maxn],wv[maxn],ws[maxn]; int cmp(int *r,int a,int b,int l) {return r[a]==r[b]&&r[a+l]==r[b+l];}//yuan lai zhi qian ba zhe li de l cuo dang cheng 1 le ... void da(int *r,int *sa,int n,int m) { int i,j

HDU5008 Boring String Problem(后缀数组 + 二分 + 线段树)

题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=5008 Description In this problem, you are given a string s and q queries. For each query, you should answer that when all distinct substrings of string s were sorted lexicographically, which one is

HDU5853 Jong Hyok and String(二分 + 后缀数组)

题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=5853 Description Jong Hyok loves strings. One day he gives a problem to his friend you. He writes down n strings Pi in front of you, and asks m questions. For i-th question, there is a string Qi. We

HDU 3518 Boring counting(后缀数组啊 求字符串中不重叠的重复出现至少两次的子串的个数)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3518 Problem Description 035 now faced a tough problem,his english teacher gives him a string,which consists with n lower case letter,he must figure out how many substrings appear at least twice,moreover

HDU 5008西安网络赛B题:后缀数组求第k小子串

思路:尼玛,这题搞了一天了,比赛的时候用了n^2的方法绝对T了,然后今天看别人代码看了一天才知道.后面感觉也挺容易的,就是没想到,之前做过SPOJ 694 705求过不同子串了,知道怎么求不同子串个数了,但是比赛的时候这个技巧竟然抛在脑后了,然后就不会了. 但是今天自己用了自己的两个后缀数组的模板(倍增和DC3)的都WA了,搞得自己真想跳楼去了!! 到现在都不知道到底是哪里错了,处理的方法和标准做法都一样,但是就是WA,然后用了别人的模板,再用自己的处理方法就过了,怀疑自己的两个模板是不是哪里错

HDU - 4552 怪盗基德的挑战书 (后缀数组)

Description "在树最美丽的那天,当时间老人再次把大钟平均分开时,我会降临在灯火之城的金字塔前,带走那最珍贵的笑容."这是怪盗基德盗取巴黎卢浮宫的<蒙娜丽莎的微笑>这幅画时,挑战书上的内容. 但这次,怪盗基德的挑战书上出现了一串串小写字母"aaab sdfeeddd...".柯南以小学生的眼睛,超凡高中生的头脑,快速统计各种字母频率,字符串长度,并结合挑战书出现的时间等信息,试图分析怪盗基德的意图.最后,他将线索锁定在字符串的循环次数上.并且进