USACO 17DEC Standing Out from the Herd P 题解

题目传送门

题目大意: 给出 N N N 个字符串,求出每个字符串拥有多少个本质不同的且不被其他字符串包含的子串。

题解

广义后缀自动机裸题,造的时候标记一下包含前缀的状态属于哪个字符串,造出来之后把后缀链接树也造出来,假如一个状态的子树内的所有状态都属于同一个字符串,那么这个状态就只属于哪个字符串,加上他的贡献即可,假如子树内不是都属于同一个字符串,说明这个状态包含的子串在不同的字符串中出现过,就不可能提供贡献了。

代码如下:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define maxn 200010
#define ll long long

int T,n,ans[maxn];
char s[maxn];
struct state{
	int len,link,next[26],belong;
}st[maxn];
int id=0,last,now,p,q;
void extend(int x,int be)
{
	now=++id;
	st[now].len=st[last].len+1;st[now].belong=be;
	for(p=last;p!=-1&&!st[p].next[x];p=st[p].link)st[p].next[x]=now;
	if(p!=-1)
	{
		q=st[p].next[x];
		if(st[p].len+1==st[q].len)st[now].link=q;
		else
		{
			int clone=++id;
			st[clone]=st[q];st[clone].len=st[p].len+1;
			for(;p!=-1&&st[p].next[x]==q;p=st[p].link)st[p].next[x]=clone;
			st[q].link=st[now].link=clone;
		}
	}
	last=now;
}
struct edge{int y,next;};
edge e[maxn];
int first[maxn],len=0;
void buildroad(int x,int y){e[++len]=(edge){y,first[x]};first[x]=len;}
void dfs(int x)
{
	for(int i=first[x];i;i=e[i].next)
	{
		dfs(e[i].y);
		if(!st[x].belong)st[x].belong=st[e[i].y].belong;
		else if(st[x].belong!=st[e[i].y].belong)st[x].belong=-1;
	}
	if(st[x].belong!=-1)ans[st[x].belong]+=st[x].len-st[st[x].link].len;
}

int main()
{
	scanf("%d",&T);
	st[0].link=-1;
	for(int j=1;j<=T;j++)
	{
		scanf("%s",s+1);n=strlen(s+1);last=0;
		for(int i=1;i<=n;i++)extend(s[i]-'a',j);
	}
	for(int i=1;i<=id;i++)buildroad(st[i].link,i);
	dfs(0);
	for(int i=1;i<=T;i++)printf("%d\n",ans[i]);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值