您的位置:首页 > 其它

Hdu-5769 Substring (SA后缀数组)

2016-07-29 21:43 435 查看

Substring

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)

Total Submission(s): 485    Accepted Submission(s): 202


[align=left]Problem Description[/align]
?? is practicing his program skill, and now he is given a string, he has to calculate the total number of its distinct substrings.

But ?? thinks that is too easy, he wants to make this problem more interesting.

?? likes a character X very much, so he wants to know the number of distinct substrings which contains at least one X.

However, ?? is unable to solve it, please help him.
 

[align=left]Input[/align]
The first line of the input gives the number of test cases T;T test cases follow.

Each test case is consist of 2 lines:

First line is a character X, and second line is a string S.

X is a lowercase letter, and S contains lowercase letters(‘a’-‘z’) only.

T<=30

1<=|S|<=10^5

The sum of |S| in all the test cases is no more than 700,000.
 

[align=left]Output[/align]
For each test case, output one line containing “Case #x: y”(without quotes), where x is the test case number(starting from 1) and y is the answer you get for that case.

 

[align=left]Sample Input[/align]

2
a
abc
b
bbb

 

[align=left]Sample Output[/align]

Case #1: 3
Case #2: 3

HintIn first case, all distinct substrings containing at least one a: a, ab, abc.
In second case, all distinct substrings containing at least one b: b, bb, bbb.

 
题意:给你一个字符和一个字符串,问你字符串中包含这个字符的不同子串的个数。

分析:求出所有后缀后边最近的要求字符的位置f[i],对于后缀sa[i],对答案的贡献就是n - max(sa[i]+height[i],f[sa[i]])。

#include<iostream>
#include<string>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<set>
#include<map>
#include<vector>
#include<cstring>
#include<stack>
#include<cmath>
#include<queue>
using namespace std;
#define INF 0x3f3f3f3f
//rank从0开始
//sa从1开始,因为最后一个字符(最小的)排在第0位
//height从2开始,因为表示的是sa[i-1]和sa[i]
const int MAXN = 100005;
int T,n,m,Rank[MAXN],sa[MAXN],X[MAXN],Y[MAXN],height[MAXN],s[MAXN],f[MAXN];
int buc[MAXN];
char str[MAXN],C[2];
void calheight(int n)
{
int i , j , k = 0;
for(i = 1 ; i <= n ; i++) Rank[sa[i]] = i;
for(i = 0 ; i < n ; height[Rank[i++]] = k)
for(k?k--:0 , j = sa[Rank[i]-1] ; s[i+k] == s[j+k] ; k++);
}
bool cmp(int *r,int a,int b,int l)
{
return (r[a] == r[b] && r[a+l] == r[b+l]);
}
void suffix(int n,int m = 128)
{
int i , l , p , *x = X , *y = Y;
for(i = 0 ; i < m ; i ++) buc[i] = 0;
for(i = 0 ; i < n ; i ++) buc[ x[i] = s[i] ] ++;
for(i = 1 ; i < m ; i ++) buc[i] += buc[i-1];
for(i = n - 1; i >= 0 ; i --) sa[ --buc[ x[i] ]] = i;
for(l = 1,p = 1 ; p < n ; m = p , l *= 2)
{
p = 0;
for(i = n-l ; i < n ; i ++) y[p++] = i;
for(i = 0 ; i < n ; i ++) if(sa[i] >= l) y[p++] = sa[i] - l;
for(i = 0 ; i < m ; i ++) buc[i] = 0;
for(i = 0 ; i < n ; i ++) buc[ x[y[i]] ] ++;
for(i = 1 ; i < m ; i ++) buc[i] += buc[i-1];
for(i = n - 1; i >= 0 ; i --) sa[ --buc[ x[y[i]] ] ] = y[i];
for(swap(x,y) , x[sa[0]] = 0 , i = 1 , p = 1 ; i < n ; i ++)
x[ sa[i] ] = cmp(y,sa[i-1],sa[i],l) ? p-1 : p++;
}
calheight(n-1);//后缀数组关键是求出height,所以求sa的时候顺便把rank和height求出来
}
int main()
{
scanf("%d",&T);
for(int t = 1;t <= T;t++)
{
scanf("%s",C);
scanf("%s",str);
int n = strlen(str);
for(int i = 0;i < n;i++) s[i] = str[i];
s
= 0;
int now = n;
for(int i = n-1;i >= 0;i--)
{
if(str[i] == C[0]) now = i;
f[i] = now;
}
suffix(n+1,128);
long long tot = 1ll*n - max(sa[1],f[sa[1]]);
for(int i = 2;i <= n;i++)
tot += 1ll*n - max(sa[i]+height[i],f[sa[i]]);
printf("Case #%d: %I64d\n",t,tot);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: