SPOJ - Distinct Substrings / SPOJ - New Distinct Substrings(后缀数组 - 不相同子串个数)

C - Distinct Substrings
Time Limit:159MS     Memory Limit:1572864KB     64bit IO Format:%lld & %llu

Description

Given a string, we need to find the total number of its distinct substrings.

Input

T- number of test cases. T<=20;
Each test case consists of one string, whose length is <= 1000

Output

For each test case output one number saying the number of distinct substrings.

Example

Sample Input:
2
CCCCC
ABABA

Sample Output:
5
9

Explanation for the testcase with string ABABA: 
len=1 : A,B
len=2 : AB,BA
len=3 : ABA,BAB
len=4 : ABAB,BABA
len=5 : ABABA
Thus, total number of distinct substrings is 9.

Hint

Added by:Prasanna
Date:2006-01-13
Time limit:0.159s
Source limit:50000B
Memory limit:1536MB
Cluster:Cube (Intel G860)
Languages:All except: NODEJS PERL 6 VB.net
Resource:ByteCode '06

题意:给出一个字符串,求不相同子串个数。

后缀数组裸题,求出一个字符串所有子串个数后,减去height的和就OK。


#include <stdio.h>
#include <math.h>
#include <string.h>
#include <algorithm>
#include <queue>
#include <iostream>
#include <assert.h>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;

const int M = 1e4 + 10;
int w[M];
int rankk[M * 2];
int sa[M];
int height[M];
char s[M];

void get_sa_hei(int len)
{
  static int m[M], tmp[M];
  //int len = strlen(s + 1);
  memset(rankk, 0, sizeof(int) * len * 2);
  for (int i = 0; i <= 255; i++) w[i] = 0;
  for (int i = 1; i <= len; i++) w[s[i]]++;
  for (int i = 1; i <= 255; i++) w[i] += w[i - 1];
  for (int i = len; i; i--) tmp[w[s[i]]--] = i;
  rankk[tmp[1]] = 1;
  for (int i = 2; i <= len; i++)
    rankk[tmp[i]] = rankk[tmp[i-1]] + (s[tmp[i]] != s[tmp[i-1]]);

  //get sa  用基数排序
  for (int k = 1; k <= len; k <<= 1) {
    for (int i = 0; i <= len; i++) w[i] = 0;
    for (int i = 1; i <= len; i++) w[rankk[i+k]]++;
    for (int i = 1; i <= len; i++) w[i] += w[i-1];
    for (int i = len; i; i--) m[w[rankk[i+k]]--] = i;

    for (int i = 0; i <= len; i++) w[i] = 0;
    for (int i = 1; i <= len; i++) w[rankk[i]]++;
    for (int i = 1; i <= len; i++) w[i] += w[i-1];
    for (int i = len; i; i--) tmp[w[rankk[m[i]]]--] = m[i];

    m[tmp[1]] = 1;
    for (int i = 2; i <= len; i++)
      m[tmp[i]] = m[tmp[i-1]] + (rankk[tmp[i]] != rankk[tmp[i-1]] || rankk[tmp[i]+k] != rankk[tmp[i-1]+k]);
    for (int i = 1; i <= len; i++) rankk[i] = m[i];
  }
  for (int i = 1; i <= len; i++) sa[rankk[i]] = i;

  //get height
  for (int i = 1, j = 0; i <= len; i++) {
    if (rankk[i] == 1) continue;
    for (j ? j-- : 0; s[sa[rankk[i]-1]+j] == s[i+j]; j++);
    height[rankk[i]] = j;
  }
}

int main()
{
  int cascnt;
  cin >> cascnt;
  while (cascnt--) {
    scanf("%s", s + 1);
    int len = strlen(s + 1);
    get_sa_hei(len);
    int ans = len * (len + 1) / 2;
    for (int i = 1; i <= len; i++) {
      ans -= height[i];
    }
    printf("%d\n", ans);
  }
  return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值