广义后缀自动机hiho1457

哇我感觉我终于掌握广义后缀自动机了

1.后缀链接保证了 被指向的点的最长串+1=起点的最小串

2.正向链接相当于将起点代表的串的集合加一个字符然后转移到目标点

3.然后还要分连续转移和不连续转移,分点的时候就相当于把原来的串分出来然后凑成连续的转移

这题不要照着hiho上的题解写,慢的要死,而且编程复杂度也是刚刚的。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string.h>
using namespace std;
const int mod = 1000000007;
typedef long long ll;
struct treee
{
	int son[11]; ll value; int maxx;
	int fa;
};
treee tree[4000000];
int root=1,diantot=2;
char s[1000020];
void getstruct(char *s, int tot)
{
	int temp = root; tree[root].maxx = 1;
	for (int i = 0; i < tot; i++)
	{
		int kind = s[i] - '0';
		if (tree[temp].son[kind])
		{
			if (tree[tree[temp].son[kind]].maxx == tree[temp].maxx + 1)//这是连续转移就相当于是原串了
			{
				temp = tree[temp].son[kind];
				continue;
			}
			else
			{
				int changeson = tree[temp].son[kind];//因为不是连续转移所以,新串不与原串重合那么我们要把有用的集合分出来
				tree[diantot] = tree[changeson]; tree[diantot].value = 0; tree[diantot].maxx = tree[temp].maxx + 1;
			     tree[changeson].fa = diantot;
				while (temp&&tree[temp].son[kind] == changeson)
					tree[temp].son[kind] = diantot,
					tree[diantot].value += (tree[temp].value * 10 + (tree[temp].maxx-tree[tree[temp].fa].maxx)*kind),
					tree[diantot].value%=mod,temp=tree[temp].fa;
				tree[changeson].value -= tree[diantot].value; tree[changeson].value = (tree[changeson].value + mod) % mod;
				temp = diantot++;
			}
		}
		else
		{//这一部分和普通后缀自动机一样
			int last = diantot;
			tree[last].maxx = tree[temp].maxx + 1;
			while (temp&&tree[temp].son[kind] == 0)tree[temp].son[kind] = last, 
				tree[last].value += (tree[temp].value * 10 + (tree[temp].maxx - tree[tree[temp].fa].maxx)*kind), tree[diantot].value %= mod, 
				temp = tree[temp].fa;
			if (temp)
			{
				if (tree[temp].maxx == tree[tree[temp].son[kind]].maxx - 1)tree[last].fa = tree[temp].son[kind];
				else
				{
					int cson = tree[temp].son[kind];
					diantot++; int newson = diantot;
					tree[newson] = tree[cson]; tree[newson].maxx = tree[temp].maxx + 1; tree[newson].value = 0;
					tree[cson].fa = newson; tree[last].fa = newson;
					while (temp&&tree[temp].son[kind] == cson)tree[temp].son[kind] = newson, 
						tree[newson].value += (tree[temp].value * 10 + (tree[temp].maxx - tree[tree[temp].fa].maxx)*kind),
						tree[newson].value %= mod,temp=tree[temp].fa;
					tree[cson].value -= tree[newson].value; tree[cson].value = (tree[cson].value + mod) % mod;
				}
			}
			else
				tree[diantot].fa = root;
			diantot++; temp = last;
		}
	}
}
int n;
int main()
{
	scanf("%d", &n);
	while (n--)
	{
		scanf("%s", s); int len = strlen(s);
		getstruct(s, len);
	}
	ll ans = 0;
	for (int i = diantot - 1; i > 1; i--)
	{
		ans += tree[i].value;
		ans %= mod;
	}
	ans = (ans + mod) % mod;
	printf("%lld\n", ans);
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值