HDU6194(後綴數組 + rmq)

string string string

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1672    Accepted Submission(s): 482


Problem Description
Uncle Mao is a wonderful ACMER. One day he met an easy problem, but Uncle Mao was so lazy that he left the problem to you. I hope you can give him a solution.
Given a string s, we define a substring that happens exactly k times as an important string, and you need to find out how many substrings which are important strings.
 

Input
The first line contains an integer T (T100) implying the number of test cases.
For each test case, there are two lines:
the first line contains an integer k (k1) which is described above;
the second line contain a string s (length(s)105).
It's guaranteed that length(s)2106.
 

Output
For each test case, print the number of the important substrings in a line.
 

Sample Input
2 2 abcabc 3 abcabcabcabc
 

Sample Output
6 9
 

Source
 

Recommend

liuyiding   |   We have carefully selected several similar problems for you:  6216 6215 6214 6213 6212 


解題思路:後綴數組,先處理出height數組,然後每次取連續的k個前綴,求他們的lcp,就是在這段區間出現k次的字符串的數量,但是這些字符串並不是每個字符串都出現k次,可能會出現大於k次的情況,我們減去這部分就行,在這段區間的上邊界和下邊界各處理一下就行,我們可以用st表或者線段樹維護一下區間lcp最小值就行。注意:每次tp數組或者rrank數組要清0,不然會影響到height的計算。。


#include <bits/stdc++.h>
using namespace std;
const int maxn = 100000 + 10;
typedef long long LL;
int kk;
int dp[maxn][30];
int Log[maxn];
char s[maxn];
int n, m;
int a[maxn];//原數組
int rrank[maxn];//第一關鍵字
int Rank[maxn];//第i個前綴排第幾
int tp[maxn];//第二關鍵字,序號爲第二關鍵字的排名,值爲對應的第一關鍵字的位置
int c[maxn];//用於基數排序用的數組
int Sa[maxn];//後綴數組,排名爲i的後綴是哪一個後綴
int Height[maxn];//排名爲i的後綴與排名爲i - 1的後綴的lcp
bool judge(int *x, int loc, int ww)
{
    if(x[Sa[loc]] == x[Sa[loc - 1]] && x[Sa[loc] + ww] == x[Sa[loc - 1] + ww]) return true;
    else return false;
}
void suffix()
{
    memset(tp, -1, sizeof(tp));//注意,一定要清0
    for(int i = 1; i <= n; i++) rrank[i] = a[i];
    for(int i = 1; i <= n; i++) tp[i] = i;
    for(int i = 0; i <= 128; i++) c[i] = 0;
    for(int i = 1; i <= n; i++) c[rrank[tp[i]]]++;
    for(int i = 1; i <= 128; i++) c[i] += c[i - 1];
    for(int i = n; i >= 1; i--) Sa[c[rrank[tp[i]]]--] = tp[i];
    m = 128;
    for(int w = 1, p = 0; w <= n; w += w, m = p)
    {
        p = 0;
        for(int i = n - w + 1; i <= n; i++) tp[++p] = i;

        for(int i = 1; i <= n; i++)
        {
            if(Sa[i] > w) tp[++p] = Sa[i] - w;
        }
        for(int i = 0; i <= m; i++) c[i] = 0;
        for(int i = 1; i <= n; i++) c[rrank[tp[i]]]++;
        for(int i = 1; i <= m; i++) c[i] += c[i - 1];
        for(int i = n; i >= 1; i--) Sa[c[rrank[tp[i]]]--] = tp[i];
        for(int i = 0; i <= n; i++) tp[i] = rrank[i];//重新計算rank的值
        rrank[Sa[1]] = 1;
        p = 1;
        for(int i = 2; i <= n; i++)
        {
            if(judge(tp, i, w)) rrank[Sa[i]] = p;
            else rrank[Sa[i]] = ++p;
        }
        if(p >= n) break;
    }
    for(int i = 1; i <= n; i++)
    {
        Rank[Sa[i]] = i;
    }
    int k = 0;
    Height[1] = 0;
    for(int i = 1; i <= n; i++)
    {
        if(k) k--;
        while(a[i + k] == a[Sa[Rank[i] - 1] + k])
        {
            k++;
        }
        Height[Rank[i]] = k;
    }
}
void initRmq()
{
    Log[0] = -1;
    for(int i = 1; i <= n; i++)
    {
        if((i&(i - 1)) == 0) Log[i] = Log[i - 1] + 1;
        else Log[i] = Log[i - 1];
        dp[i][0] = Height[i];
    }
    for(int j = 1; j <= 25; j++)
    {
        for(int i = 1; i <= n && (i + (1<<j) - 1) <= n; i++)
        {
            dp[i][j] = min(dp[i][j - 1], dp[i + (1<<(j - 1))][j - 1]);
        }
    }
}
int rmq(int l, int r)
{
    int d = r - l + 1;
    d = Log[d];
    return min(dp[l][d], dp[r - (1<<d) + 1][d]);
}
void init()
{
    n = strlen(s);
    memset(Height, 0, sizeof(Height));
    memset(a, -1, sizeof(a));//注意,一定要重置。在這裏wa了無數次
    for(int i = 0; i < n; i++)
    {
        a[i + 1] = s[i];
    }
}
int main()
{
    //freopen("C:\\Users\\creator\\Desktop\\in1.txt","r",stdin) ;
    //freopen("C:\\Users\\creator\\Desktop\\out.txt","w",stdout) ;
    int T;
    scanf("%d", &T);
    while(T--)
    {
        scanf("%d", &kk);
        scanf("%s", s);
        init();
        suffix();
        initRmq();
        LL ans = 0;
        if(kk == 1)
        {
            for(int i = 1; i <= n; i++)
            {
                LL value = (LL)(n - Sa[i] + 1);
                LL value1, value2;
                value1 = (LL)Height[i];
                if(i + 1 <= n) value2 = (LL)Height[i + 1];
                else value2 = 0;
                LL Max = max(value1, value2);
                if(value > Max) ans += value - Max;
            }
        }
        else
        {
            for(int i = 1; i + 1 <= n && i + (kk - 1) <= n; i++)
            {
                LL value = (LL)rmq(i + 1, i + (kk - 1));
                LL value1 = (LL)rmq(i, i + (kk - 1));
                LL value2;
                if(i + kk <= n) value2 = (LL)rmq(i + 1, i + kk);
                else value2 = 0;
                LL Max = max(value1, value2);
                if(value > Max) ans += value - Max;
            }
        }
        printf("%I64d\n", ans);
    }
    return 0;
}




發佈了150 篇原創文章 · 獲贊 208 · 訪問量 15萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章