Codeforces 235C 【Cyclical Quest】

Description

传送门


Solution

考虑循环同构的性质,每次相当于从最前面删去一个字符,从最后面加上一个字符。在\(SAM\)里对应着往上跳\(fa\)或不跳和走对应的字符串转移边。

考虑对于长度为\(l\)的串,最多删\(l\)次,最多加\(l\)次,所以直接在\(SAM\)上暴力删除添加字符的复杂度就是\(O(l)\)的。

那么先把字符串在后面将自己复制一遍,然后丢到\(SAM\)上跑,如果没有对应的转移边就不停地跳\(fa\),直到第一个满足是字符串的循环同构串的节点。那么这时考虑删除最前面的字符,就有两种情况,一种是\(len_{fa_{now}} + 1 =\)原字符串串长,也就是说,删去最前面的一个字符后,要往上跳\(fa\);另一种是$len_{fa_{now}} + 1 < \(当前匹配长度,这就说明删除一个字符后的\)endpos$集合没有改变,直接转移下一个边就行。

然后因为要求本质不同,所以打上时间戳标记,确保每种子串只被算一次贡献即可。


Code

#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

const int N = 1000000;

int l, fa[N * 2 + 50], son[N * 2 + 50][26], len[N * 2 + 50], vis[N * 2 + 50], siz[N * 2 + 50], num, head[N * 2 + 50], last = 1, cnt = 1;

char st[N * 2 + 50];

struct Node
{
	int next, to;
} edge[N * 2 + 50];

void Addedge(int u, int v)
{
	edge[++num] = (Node){head[u], v};
	head[u] = num;
	return;
} 

void Insert(int c)
{
	int p = last, ne = last = ++cnt;
	len[ne] = len[p] + 1; siz[ne] = 1; 
	while (!son[p][c] && p) son[p][c] = ne, p = fa[p];
	if (!p) { fa[ne] = 1; return; }
	int q = son[p][c];
	if (len[q] == len[p] + 1) { fa[ne] = q; return; }
	int sp = ++cnt;
	for (int i = 0; i < 26; i++) son[sp][i] = son[q][i];
	len[sp] = len[p] + 1;
	fa[sp] = fa[q];
	fa[q] = fa[ne] = sp;
	while (p && son[p][c] == q) son[p][c] = sp, p = fa[p];
	return;
}

void Dfs(int x)
{
//	cout << x << " len:" << len[x] << " " << endl;
	for (int i = head[x]; i; i = edge[i].next)
	{
		int v = edge[i].to;
		Dfs(v);
		siz[x] += siz[v];
	}
//	cout << x << " " << siz[x] << endl;
	return;
}

int main()
{
	scanf("%s", st + 1);
	l = strlen(st + 1);
	for (int i = 1; i <= l; i++) Insert(st[i] - 'a');
//	cout << cnt << endl;
	for (int i = 2; i <= cnt; i++) Addedge(fa[i], i);
	Dfs(1);
	int t;
	//for (int i = 1; i <= cnt; i++) printf("%d ", siz[i]); puts("");
	scanf("%d", &t);
	for (int i = 1; i <= cnt; i++) vis[i] = t;
	while (t--)
	{
		int ans = 0; 
		scanf("%s", st + 1);
		int now = 1, length = 0;
		l = strlen(st + 1);
		int yl = l;
		for (int i = yl + 1; i <= yl * 2 - 1; i++) st[i] = st[i - yl];
		l = 2 * l - 1;
		for (int i = 1; i <= l; i++)
		{
			int c = st[i] - 'a';
		//	cout << st[i] << " " << length << " " << now << endl;
			while (!son[now][c] && now) now = fa[now], length = len[now];
			if (son[now][c]) length++, now = son[now][c]; else now = 1, length = 0;
			if (length == yl) 
			{
				if (vis[now] > t) ans += siz[now], vis[now] = t;
				if (len[fa[now]] + 1 == yl) now = fa[now];
				length--;
			} 
		//	cout << now << endl;
		}
		printf("%d\n", ans);
	}
	return 0;
} 
posted @ 2020-06-12 09:48  Tian-Xing  阅读(102)  评论(0编辑  收藏  举报