【BZOJ 3172】单词

【链接】h在这里写链接


【题意】


    给你n个单词;
    这n个单词组成了一篇文章;
    问你每个单词在这篇文章中出现了多少次.
    其中每个单词之间用一个逗号隔开->组成一篇文章。
    (单词的总长度不会超过10^6)
    单词的个数小于等于200


【题解】


    后缀数组题.
    把每个字符串用一个分隔符分开来.
    然后求其后缀数组;

    然后先获取每个单词后缀的排名;
    然后往左走直到lcp小于这个单词的长度,
    然后往右走直到lcp小于这个单词的长度
    向左走和向右走的区间就是这个单词在文章中出现的次数。

    暴力做一下就好;
    如果想优化的话,感觉可以再加一个二分。
    因为长度越长,显然lcp是越来越小的。。
    啦啦啦
    但是不用加这个优化就可以过啦。
    听网上的人说的。。


【错的次数】


0

【反思】


在这了写反思

【代码】

#include<bits/stdc++.h>
using namespace std;

const int N = 1e6 + 500;
const int MAX_CHAR = 500;//每个数字的最大值。
int s[N + 10];//如果是数字,就写成int s[N+10]就好,从0开始存
int Sa[N + 10], T1[N + 10], T2[N + 10], C[N + 10];
int Height[N + 10], Rank[N + 10];

void build_Sa(int n, int m) {
	int i, *x = T1, *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 = 1; 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 getHeight(int n)
{
	int i, j, k = 0;
	for (i = 1; i <= n; i++) Rank[Sa[i]] = i;
	for (i = 0; i<n; i++) {
		if (k) k--;
		j = Sa[Rank[i] - 1];
		while (s[i + k] == s[j + k]) k++;
		Height[Rank[i]] = k;
	}
}

int n, fir[200 + 10],le[200+10];
char ts[N + 10];

int main() 
{
	//freopen("F:\\rush.txt", "r", stdin);
	int t;
	scanf("%d", &t);
	for (int ii = 1;ii <= t;ii++)
	{
		scanf("%s", ts);
		int len = strlen(ts);
		le[ii] = len;
		fir[ii] = n;
		for (int i = 0; i < len; i++)
			s[n++] = ts[i];
		s[n++] = 'z' + ii;//不能是字符类型,可能会爆掉!
	}
	s[n] = 0;
	build_Sa(n + 1, MAX_CHAR);//注意调用n+1
	getHeight(n);
	for (int i = 1; i <= t; i++)
	{
		int temp = Rank[fir[i]],temp1 = temp,ans = 1;
		while (temp - 1 >= 1 && Height[temp] >= le[i])
		{
			ans++;
			temp--;
		}
		while (temp1 + 1 <= n && Height[temp1 + 1] >= le[i])
		{
			ans++;
			temp1++;
		}
		printf("%d\n", ans);
	}
	return 0;
}


posted @ 2017-10-04 18:44  AWCXV  阅读(137)  评论(0编辑  收藏  举报