【YBTOJ】【BZOJ 3620】似乎在梦中见过的样子

题目大意:

已知一个字符串 \(S\),求它有多少个形如 \(A+B+A\) 的子串(\(|A|\geq k,|B|\geq 1\))。位置不同其他性质相同的子串算不同子串,位置相同但拆分不同的子串算同一子串。

\(|S|\leq1.5\times10^4,k\leq100\)

正文:

本题暴力枚举左端点然后 KMP,由于 \(\mathcal{O}(n)\) 有点吃力,所以需要卡卡常。

代码:

const int N = 1e6 + 10;

inline ll READ()
{
	ll x = 0, f = 1;
	char c = getchar();
	while (c != '-' && (c < '0' || c > '9')) c = getchar();
	if (c == '-') f = -f, c = getchar();
	while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0', c = getchar();
	return x * f;
}

char s[N];
int nxt[N], ans;
int n, k;

inline void KMP (char *s, int n, int op = 1)
{
	int j = 0;
	for (int i = op; i < n; i++)
	{
		while (j && s[i] != s[j]) j = nxt[j];
		if (s[i] == s[j]) j++;
		if(op) nxt[i + 1] = j;
		else
		{
			if (2 * j > i) j = nxt[j];
			if (j >= k) ans ++; 
		}
	}
	return;
}

int main()
{
	scanf("%s", s);
	k = READ();
	n = strlen(s);
	for (int i = 1; i < n; i++)
	{
		KMP (s + i - 1, n - i + 1);
		KMP (s + i - 1, n - i + 1, 0);
	}
	printf ("%d\n", ans);
	return 0;
}

posted @ 2021-05-06 16:48  Jayun  阅读(84)  评论(0编辑  收藏  举报