HDU 4622 Reincarnation

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.
 


建立n个后缀自动机然后存下全部信息即可

#include<cstdio>  
#include<cstring>  
#include<cmath>  
#include<algorithm>  
#include<queue>  
using namespace std;  
typedef long long ll;  
const int maxn = 2005;

class SAM
{
	const static int maxn=100005;	//节点个数
	const static int size = 26;		//字符的范围
	const static char base='a';		//字符的基准

	class node
	{
	public:
		node *fa, *next[size];
		int len, cnt;
		node* clear(int x)
		{ 
			fa = 0; len = x; cnt = 0; 
			memset(next, 0, sizeof(next));
			return this;
		}
	}nd[maxn];						//节点的设置
	
	node *root, *last;				//根节点,上一个节点
	int tot;						//总节点数
public:
	void clear()
	{ 
		last = root = &nd[tot = 0];
		nd[0].clear(0);
		nd[0].cnt = 1;
	}								//初始化
	int insert(char ch)
	{
		node *p = last, *np = nd[++tot].clear(p->len + 1);
		last = np;
		int x = ch - base;
		while (p&&p->next[x] == 0) p->next[x] = np, p = p->fa;
		if (p == 0) { np->fa = root; return np->cnt = np->len - np->fa->len; }

		node* q = p->next[x];
		if (p->len + 1 == q->len) { np->fa = q; return np->cnt = np->len - np->fa->len; }

		node *nq = nd[++tot].clear(p->len + 1);
		memcpy(nq->next, q->next, sizeof q->next);
		nq->fa = q->fa;
		q->fa = np->fa = nq;
		while (p &&p->next[x] == q) p->next[x] = nq, p = p->fa;
		return np->cnt = np->len - np->fa->len;
	}								//插入操作
}sam;

int T, n, l, r;
char s[maxn];
int f[maxn][maxn];

int main()
{
	scanf("%d", &T);
	while (T--)
	{
		scanf("%s", s);
		memset(f, 0, sizeof(f));
		for (int i = 0; s[i]; i++)
		{
			sam.clear();
			for (int j = i; s[j]; j++) f[i + 1][j + 1] = f[i + 1][j] + sam.insert(s[j]);
		}
		scanf("%d", &n);
		while (n--)
		{
			scanf("%d%d", &l, &r);
			printf("%d\n", f[l][r]);
		}
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值