hdu 5769 Substring 後綴數組

題意:求一個字符串中包含字符ch的所有子串


思路:訓練的時候想到是用後綴數組,但是不停地tle,最後還是沒有ac,事後總結了下相關的性質

   (1)一個字符串的所有子串必定是屬於某個後綴的前綴, 如s = “acabd”,後綴0包含的子串是“a”, “ac”, “aca”, “acab”, “acabc”,後綴1包含的子串是“c”,“ca”, “cab”, “cabd”,後綴2包含的兒串是“a”, “ab”, “abd”, 後綴3包含的子串是“b”, “bd”, 後綴4包含的子串是“d”;

(2)上述所有後綴的前綴是有重複的,例如後綴0的“a”和後綴2的“a”,那麼可以得到一條公式:後綴i貢獻的子串個數 = 後綴i長度 - height[i];

(3)後綴i長度 = 字符串長度 - sa[i];

(4)算後綴數組時,一般加上'\0',也就是算出來後sa[0] = len, rank[len] = 0,;(len爲字符串長度)


鏈接:http://acm.hdu.edu.cn/showproblem.php?pid=5769


#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int maxn = 100005;

char s[maxn], s0[10];
int sa[maxn], t[maxn], t2[maxn], c[maxn];
int ran[maxn], h[maxn];
int pos[maxn];

void build_sa(int n, int m)
{
	int i, *x = t, *y = t2;
	for (i = 0; i < m; i++) c[i] = 0;
	for (i = 0; i < n; i++) c[x[i] = s[i]]++;
	for (i = 1; i < m; i++) c[i] += c[i - 1];
	for (i = n - 1; i >= 0; i--) sa[--c[x[i]]] = i;
	for (int k = 1; k <= n; k <<= 1)
	{
		int p = 0;
		for (i = n - k; i < n; i++) y[p++] = i;
		for (i = 0; i < n; i++) if (sa[i] >= k) y[p++] = sa[i] - k;

		for (i = 0; i < m; i++) c[i] = 0;
		for (i = 0; i < n; i++) c[x[y[i]]]++;
		for (i = 0; i < m; i++) c[i] += c[i - 1];
		for (i = n - 1; i >= 0; i--) sa[--c[x[y[i]]]] = y[i];

		swap(x, y);
		p = 1; x[sa[0]] = 0;
		for (i = 1; i < n; i++)
			x[sa[i]] = y[sa[i - 1]] == y[sa[i]] && y[sa[i - 1] + k] == y[sa[i] + k] ? p - 1 : p++;
		if (p >= n) break;
		m = p;
	}
}

void get_height(int n)
{
	int k = 0;
	for (int i = 0; i <= n; i++) ran[sa[i]] = i; //記住這裏是等於號
	for (int i = 0; i < n; i++)
	{
		if (k) k--;
		int j = sa[ran[i] - 1];//這裏千萬不要寫成ran[k] - 1,調了大半天沒看出來
		while (s[i + k] == s[j + k]) k++;
		h[ran[i]] = k;
	}
}

int main()
{
	int t, cas = 1;
	scanf("%d", &t);
	while (t--)
	{
		scanf("%s", s0);
		scanf("%s", s);
		char ch = s0[0];
		int len = strlen(s);
		build_sa(len + 1, 128);
		get_height(len);
		int res;
		bool flag = false;
		pos[len - 1] = -1;
		for (int i = len - 1; i >= 0; i--)
		{
			if (s[i] == ch)
				flag = true, res = i;
			if (flag)
				pos[i] = res;
			else
				pos[i] = -1;
		}
		long long ans = 0;
		for (int i = 0; i <= len; i++)
		{
			if (pos[sa[i]] != -1)
				ans = ans + len - max(sa[i] + h[i], pos[sa[i]]);
		}
		printf("Case #%d: %I64d\n", cas++, ans);
	}
	return 0;
}




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章