您的位置:首页 > 其它

HDU 4622 Reincarnation( 任意区间子串的长度, 后缀数组+RMQ)

2015-01-23 19:00 381 查看
题目大意:给你一个字符串,给你N次查询,每次给你一个区间让你求出这个区间里面有多少子串。

解题思路:我们肯定要枚举位置,然后找公共子串然后再去掉重复的,但是他的地址对应的rank不是连续的,如果暴力找的话会n*n会超时。

从这个博客学习到一种方法:首先对整个字符串求一次sa[]以及height[],之后对于任意区间[L, R],遍历一遍sa[],只要起点在[L, R]内的后缀就需要进行统计,类似于1)中的方法,不过有一个地方要特别注意的就是全部的sa[]不一定就是区间内的sa[],这是因为区间内的后缀比较时有额外的长度限制。可以证明遍历的过程要遵循如下的规则:

后缀s1和后缀s2现在是两个待比较的后缀,s1在前,s2在后,其起点都在区间[L, R]内,并设两串在区间中的长度为 len1, len2, 其全局的最长公共前缀为 lcp。现考虑在遍历sa[]时,如何从全局sa[]得到正确的局部sa[]:

1: lcp < len1 && lcp < len2 时说明两个串在未结束时就比较出了大小,全局和局部的sa[]统一,因此可以放心令s2作为下一个字典序后缀;

2: lcp >= len1 && lcp >= len2 时说明在其中一个串结束时,两个串对应字符都是相等的,这时需要根据len1和len2关系来决定,如果len1>len2那么就不用更换了;

3: lcp >= len1 && lcp < len2 时说明在其中一个串结束时,两个串对应字符都是相等的,由于s2的长度比s1长,因此字典序肯定大,因此需要更换当前的后缀;

4: lcp < len1 && lcp >= len2 时说明在其中一个串结束时,两个串对应字符都是相等的,由于s1的长度比s2长,因此字典序肯定大,因此不需更换当前的后缀。

其中2和4条件可以合并,如果4成立,那么必定有 len1 > len2,因此可以简化这个判断这个过程:if (len1 > len2 && lcp >= len2) 则不更换 else 更换。

 if(la > lb && lcp >= lb){不交换} else {交换};

直接理解就是给结果带来误差的情况只会是某个被lcp完全包含的后缀被排在了后面,那么它的正确位置应该是在最前面,由于在后面匹配的其长度仍未整个局部后缀的长度,而在选择下一个字典序后缀时屏蔽掉这个后缀即可。


Reincarnation

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others)

Total Submission(s): 2277    Accepted Submission(s): 795


Problem Description

Now you are back,and have a task to do:

Given you a string s consist of lower-case English letters only,denote f(s) as the number of distinct sub-string of s.

And you have some query,each time you should calculate f(s[l...r]), s[l...r] means the sub-string of s start from l end at r.

 

Input

The first line contains integer T(1<=T<=5), denote the number of the test cases.

For each test cases,the first line contains a string s(1 <= length of s <= 2000).

Denote the length of s by n.

The second line contains an integer Q(1 <= Q <= 10000),denote the number of queries.

Then Q lines follows,each lines contains two integer l, r(1 <= l <= r <= n), denote a query.

 

Output

For each test cases,for each query,print the answer in one line.

 

Sample Input

2
bbaba
5
3 4
2 2
2 5
2 4
1 4
baaba
5
3 3
3 4
1 4
3 5
5 5

 

Sample Output

3
1
7
5
8
1
3
8
5
1
Hint
I won't do anything against hash because I am nice.Of course this problem has a solution that don't rely on hash.

 

Source

2013 Multi-University Training Contest 3

 

#include <algorithm>
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <iomanip>
#include <stdio.h>
#include <string>
#include <queue>
#include <cmath>
#include <stack>
#include <ctime>
#include <map>
#include <set>
#define eps 1e-9
///#define M 1000100
///#define LL __int64
#define LL long long
///#define INF 0x7ffffff
#define INF 0x3f3f3f3f
#define PI 3.1415926535898
#define zero(x) ((fabs(x)<eps)?0:x)
#define mod 1000000007

#define Read() freopen("autocomplete.in","r",stdin)
#define Write() freopen("autocomplete.out","w",stdout)
#define Cin() ios::sync_with_stdio(false)

using namespace std;

inline int read()
{
char ch;
bool flag = false;
int a = 0;
while(!((((ch = getchar()) >= '0') && (ch <= '9')) || (ch == '-')));
if(ch != '-')
{
a *= 10;
a += ch - '0';
}
else
{
flag = true;
}
while(((ch = getchar()) >= '0') && (ch <= '9'))
{
a *= 10;
a += ch - '0';
}
if(flag)
{
a = -a;
}
return a;
}
void write(int a)
{
if(a < 0)
{
putchar('-');
a = -a;
}
if(a >= 10)
{
write(a / 10);
}
putchar(a % 10 + '0');
}

const int maxn = 2050;

int wa[maxn], wb[maxn], wv[maxn], ws1[maxn];
int sa[maxn];

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

void da(int *r, int *sa, int n, int m)
{
int i, j, p, *x = wa, *y = wb;
for(i = 0; i < m; i++) ws1[i] = 0;
for(i = 0; i < n; i++) ws1[x[i] = r[i]]++;
for(i = 1; i < m; i++) ws1[i] += ws1[i-1];
for(i = n-1; i >= 0; i--) sa[--ws1[x[i]]] = i;

for(j = 1, p = 1; p < n; j <<= 1, m = p)
{
for(p = 0, 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 < n; i++) wv[i] = x[y[i]];
for(i = 0; i < m; i++) ws1[i] = 0;
for(i = 0; i < n; i++) ws1[wv[i]]++;
for(i = 1; i < m; i++) ws1[i] += ws1[i-1];
for(i = n-1; i >= 0; i--) sa[--ws1[wv[i]]] = y[i];
for(swap(x, y), p = 1, x[sa[0]] = 0, i = 1; i < n; i++)
x[sa[i]] = cmp(y, sa[i-1], sa[i], j)?p-1:p++;
}
}

int rank[maxn], height[maxn];
void calheight(int *r, int *sa, int n)
{
int i, j, k = 0;
for(i = 1; i <= n; i++) rank[sa[i]] = i;
for(int i = 0; i < n; height[rank[i++]] = k)
for(k?k--:0, j = sa[rank[i]-1]; r[i+k] == r[j+k]; k++);
return ;
}

int dp[maxn][30];

void RMQ(int len)
{
for(int i = 1; i <= len; i++)
dp[i][0] = height[i];
for(int j = 1; 1<<j <= maxn; j++)
{
for(int i = 1; i+(1<<j)-1 <= len; i++)
dp[i][j] = min(dp[i][j-1], dp[i+(1<<(j-1))][j-1]);
}
}
int lg[maxn];

int querry(int l, int r)
{
int k = lg[r-l+1];
return min(dp[l][k], dp[r-(1<<k)+1][k]);
}

void init()
{
lg[0] = -1;
for (int i = 1; i < maxn; ++i)
lg[i] = lg[i>>1] + 1;
}
char str[maxn];
int seq[maxn];

int Del(int l, int r, int n)
{
int ans = (r-l+2)*(r-l+1)/2;
int last = -1;
int k = r-l+1;
for(int i = 1; i <= n; i++)
{
if(!k) break;
if(sa[i] < l || sa[i] > r) continue;
k--;
if(last == -1)
{
last = i;
continue;
}
int a = last;
int b = i;
if(a > b) swap(a, b);
int lcp = querry(a+1, b);
int la = r-sa[last]+1;
int lb = r-sa[i]+1;
if(la > lb && lcp >= lb){}
else last = i;
ans -= min(lcp, min(la, lb));
}
return ans;
}

int main()
{
int T;
cin >>T;
init();
while(T--)
{
scanf("%s", str);
int len = strlen(str);
for(int i = 0; i < len; i++)
seq[i] = str[i]-'a'+1;
seq[len] = 0;
da(seq, sa, len+1, 27);
calheight(seq, sa, len);
RMQ(len);
int n;
int l, r;
scanf("%d",&n);
while(n--)
{
scanf("%d %d",&l, &r);
printf("%d\n", Del(l-1, r-1, len));
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: