Typesetting math: 100%

【JZOJ6379】【NOIP2019模拟2019.10.06】小w与密码(password)

题目大意

给出两个串S,T,你可以通过拼接S的某个前缀和T的某个前缀得到一个新串(S的前缀在前),求能得到多少种不同的新串。

Solution

若一个串出现了多次,设它可以被表示成s+ts+t。我们令tt更长,显然tt的一个border。尽管t有多个border,但实际上只用减去最长的border带来的影响,因为更短的border已经在这个长border计算过了。考虑把tt的后面去掉,剩下的t的一个前缀,若它在S中作为一个子串且不作为前缀出现,它就会被重复计算,减掉该前缀在S中出现次数即可。求前缀出现次数只需要将TS匹配并用next数组做一次后缀和。

Code

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int N = 100007;

long long ans;
int lens, lent, next[N], num[N];
char s[N], t[N];

int main() {
	freopen("password.in", "r", stdin);
	freopen("password.out", "w", stdout);
	scanf("%s%s", s + 1, t + 1);
	lens = strlen(s + 1);
	lent = strlen(t + 1);
	ans = 1ll * lens * lent;
	for (int i = 2, j = 0; i <= lent; ++i) {
		while (j && t[j + 1] != t[i]) j = next[j];
		if (t[j + 1] == t[i]) ++j;
		next[i] = j;
	}
	for (int i = 2, j = 0; i <= lens; ++i) {
		while (j && t[j + 1] != s[i]) j = next[j];
		if (t[j + 1] == s[i]) ++j;
		++num[j];
	}
	for (int i = lent; i >= 2; --i) num[next[i]] += num[i];
	for (int i = 2; i <= lent; ++i) if (next[i]) ans -= num[i - next[i]];
	printf("%lld\n", ans);
	return 0;
}

作者:zjlcnblogs

出处:https://www.cnblogs.com/zjlcnblogs/p/11627811.html

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @ 2019-10-06 17:27  gz-gary  阅读(394)  评论(0)    收藏  举报
more_horiz
keyboard_arrow_up dark_mode palette
选择主题
点击右上角即可分享
微信分享提示