• 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
    ", ans);
    	}
    	return 0;
    } 
    
  • 相关阅读:
    64_q2
    64_q1
    64_p10
    64_p9
    64_p8
    64_p7
    64_p6
    64_p5
    64_p4
    64_p3
  • 原文地址:https://www.cnblogs.com/Tian-Xing-Sakura/p/13097702.html
Copyright © 2020-2023  润新知