G. Gluing Pictures(SAM)

在这里插入图片描述
在这里插入图片描述

题意

给字符串 s s s t t t,你需要给 s s s 拍若干张照片,然后把它们按某种顺序拼起来得到字符串t,求最少拍多少张照片、其实就是在找最少需要多少原串中的子串构成询问串。

每次贪心地选择极长的一段拍照, S A M SAM SAM进行匹配就行了。

AC代码:

const int N = 500010;
struct SAM
{
	struct node
	{
		int parent, next[26], len;
		int cnt;
	};
	node tr[N];
	int sz[N];
	int rnk[N];
	int last = 0;
	int num = 0;
	void init()
	{
		last = 0;
		num = 0;
		tr[0].parent = -1;
	}
	void add(char ch)
	{
		int p = last;
		int t = ch - 'A';
		int now = ++num;
		tr[now].len = tr[last].len + 1;
		tr[now].cnt = 1;
		while (p != -1 && tr[p].next[t] == 0)
		{
			tr[p].next[t] = now;
			p = tr[p].parent;
		}
		if (p != -1)
		{
			int q = tr[p].next[t];
			if (tr[p].len + 1 == tr[q].len)
			{
				tr[num].parent = q;
			}
			else
			{
				tr[++num].parent = tr[q].parent;
				memcpy(tr[num].next, tr[q].next, sizeof(tr[num].next));
				tr[num].len = tr[p].len + 1;
				while (p != -1 && tr[p].next[t] == q)
				{
					tr[p].next[t] = num;
					p = tr[p].parent;
				}
				tr[now].parent = tr[q].parent = num;
			}
		}
		else
			tr[now].parent = 0;
		last = now;
	}
	void solve()
	{
		for (int i = 0; i <= num; ++i)
			sz[i] = 0;
		for (int i = 0; i <= num; ++i)
			sz[tr[i].len]++;
		for (int i = 1; i <= num; ++i)
			sz[i] += sz[i - 1];
		for (int i = 0; i <= num; ++i)
			rnk[--sz[tr[i].len]] = i;
		for (int i = num; i >= 1; --i)
		{
			tr[tr[rnk[i]].parent].cnt += tr[rnk[i]].cnt;
		}
	}
	int getAns(char ch[], int len)
	{
		int ans = 1;
		int now = 0;
		for (int i = 0; i < len; ++i)
		{
			now = tr[now].next[ch[i] - 'A'];
			if (now == 0)
			{
				++ans;
				now = tr[now].next[ch[i] - 'A'];
				if (now == 0)
					return -1;
			}
		}
		return ans;
	}
};
SAM sam;
int n;
char str[500001];
int main()
{
	ss(str);
	sam.init();
	int len = strlen(str);
	rep(i, 0, len - 1)
		sam.add(str[i]);
	sd(n);
	while (n--)
	{
		ss(str);
		len = strlen(str);
		pd(sam.getAns(str, len));
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值