HDU4622

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

题意
给出一个字符串SSS2000|S|\leq 2000,给出QQLLRRQ10000Q\leq 10000,求SS的子串S[L...R]S[L...R],有多少不同的子串。
题解
对于SS的所有S|S|个后缀,即对(S[i...S]i[1,N])(S[i...|S|],i\in[1,N])都建立一个后缀自动机。构造过程中,每添加一个字符,根据后缀连接树的性质,从i到当前字符的子串数量为len(u)len(link(u))len(u)-len(link(u)),其中uu为添加当前字符后的末状态。这样在构造iiS|S|时就可以求出区间[i,S][i,|S|]的所有子区间的子串数量。而枚举ii就可以求出[1,S][1,|S|]的所有子区间的子串数量了。
AC代码

#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
#include<vector>
#include<cmath>
#include<map>
using namespace std;
const int MAXN = 2005;
int n;
char S[MAXN];
struct SAM {
	int size, last;
	struct Node {
		int len, link;
		int next[26];
		void clear() {
			len = link = 0;
			memset(next, 0, sizeof(next));
		}
	} node[MAXN * 2];
	void init() {
		for (int i = 0; i < size; i++) {
			node[i].clear();
		}
		node[0].link = -1;
		size = 1;
		last = 0;
	}
	void insert(char x) {
		int ch = x - 'a';
		int cur = size++;
		node[cur].len = node[last].len + 1;
		int p = last;
		while (p != -1 && !node[p].next[ch]) {
			node[p].next[ch] = cur;
			p = node[p].link;
		}
		if (p == -1) {
			node[cur].link = 0;
		}
		else {
			int q = node[p].next[ch];
			if (node[p].len + 1 == node[q].len) {
				node[cur].link = q;
			}
			else {
				int clone = size++;
				node[clone] = node[q];
				node[clone].len = node[p].len + 1;
				while (p != -1 && node[p].next[ch] == q) {
					node[p].next[ch] = clone;
					p = node[p].link;
				}
				node[q].link = node[cur].link = clone;
			}
		}
		last = cur;
	}
}sam;
int Ans[MAXN][MAXN];
int main() {
	int T;
	scanf("%d", &T);
	while (T--) {
		scanf("%s", S);
		n = strlen(S);
		//枚举i
		for (int i = 0; i < n; ++i) {
			sam.init();
			int&& Temp = 0;
			//添加字符
			for(int j=i;j<n;++j){
				sam.insert(S[j]);
				Temp += sam.node[sam.last].len;
				//如果存在后缀连接边
				if (sam.node[sam.last].link != -1) {
					Temp -= sam.node[sam.node[sam.last].link].len;
				}
				//编号从1开始
				Ans[i + 1][j + 1] = Temp;
			}
		}
		int Q;
		scanf("%d", &Q);
		while (Q--) {
			int Left, Right;
			scanf("%d%d", &Left, &Right);
			printf("%d\n", Ans[Left][Right]);
		}
	}
	return 0;
}
posted on 2020-01-26 15:16  SCU_GoodGuy  阅读(185)  评论(0)    收藏  举报