SOJ-4484-后缀数组

题目链接 :  SOJ-4484



 
 

The Graver Robbers' Chronicles

Description

One day, Kylin Zhang and Wu Xie are trapped in a graveyard. They find an ancient piece of parchment with a cipher string. After discussion and analysis, they find the password is the total number of the cipher string's distinct substrings. Although Kylin Zhang is powerful and always help his friends get rid of danger, this time he is helpless beacause he is not good at math and programming. As a smart Acmer, can you help them solve this problem so that they can escape from this horrible graveyard.

Input

The first line is an integer T stands for the number of test cases. Then T test case follow. For each test case there is one string. Constraints: T is no bigger than 30. The length of string is no bigger than 50000. Every string only contains lowercase letters.

Output

For each test case, output the answer in a single line. one number saying the number of distinct substrings.

Sample Input

2 aaaaa cacac

Sample Output

5 9

Hint

For test case 2, the distinct substrings of 'cacac' are as follows: len = 1 : c , a len = 2 : ca , ac len = 3 : cac , aca len = 4 : caca , acac len = 5 : cacac Thus, total number of distinct substrings is 9.

Author

_L


题目大意:给你一个字符串,求出有多少种不同的子串(连续)包括本身  见样例


题目思路:  看了很久的后缀数组了,,一直都不太懂怎么来的,之后用模板处理一些简单的问题,,这道题关键是对后缀数组height数组的理解,,具体我这里就不描述了,,答案就是所有的子串的个数减去height数组里的值,,这里会超int,,所以要用long long  


AC代码:

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

const int maxn = 1e5;

int cntA[maxn],sa[maxn],Rank[maxn],cntB[maxn],height[maxn],A[maxn],B[maxn],tsa[maxn];
char ch[maxn];
int n;
void solve()
{
    for (int i = 0; i < 256; i ++) cntA[i] = 0;
    for (int i = 1; i <= n; i ++) cntA[ch[i-1]] ++;
    for (int i = 1; i < 256; i ++) cntA[i] += cntA[i - 1];
    for (int i = n; i; i --) sa[cntA[ch[i-1]] --] = i;
    Rank[sa[1]] = 1;
    for (int i = 2; i <= n; i ++)
    {
        Rank[sa[i]] = Rank[sa[i - 1]];
        if (ch[sa[i]-1] != ch[sa[i - 1]-1]) Rank[sa[i]] ++;
    }
    for (int l = 1; Rank[sa[n]] < n; l <<= 1)
    {
        for (int i = 0; i <= n; i ++) cntA[i] = 0;
        for (int i = 0; i <= n; i ++) cntB[i] = 0;
        for (int i = 1; i <= n; i ++)
        {
            cntA[A[i] = Rank[i]] ++;
            cntB[B[i] = (i + l <= n) ? Rank[i + l] : 0] ++;
        }
        for (int i = 1; i <= n; i ++) cntB[i] += cntB[i - 1];
        for (int i = n; i; i --) tsa[cntB[B[i]] --] = i;
        for (int i = 1; i <= n; i ++) cntA[i] += cntA[i - 1];
        for (int i = n; i; i --) sa[cntA[A[tsa[i]]] --] = tsa[i];
        Rank[sa[1]] = 1;
        for (int i = 2; i <= n; i ++)
        {
            Rank[sa[i]] = Rank[sa[i - 1]];
            if (A[sa[i]] != A[sa[i - 1]] || B[sa[i]] != B[sa[i - 1]]) Rank[sa[i]] ++;
        }
    }
    for (int i = 1, j = 0; i <= n; i ++)
    {
        if (j) j --;
        while (ch[i + j-1] == ch[sa[Rank[i] - 1] + j-1]) j ++;
        height[Rank[i]] = j;
    }
}

int main()
{
    int t;cin>>t;
    while(t--){
    scanf("%s",ch);
    n=strlen(ch);
    solve();
    long long ans = (long long)(1+n)*n/2;
    for(int i=1;i<=n;i++)
        ans-=(long long)height[i];
    cout<<ans<<endl;
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值