ACM-ICPC 2018 焦作赛区网络赛 H. String and Times(后缀自动机)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Cymbals/article/details/82716712

题目:https://nanti.jisuanke.com/t/31717

下午打的网络赛,一上来就开了这题,打算秒,结果发现题面没有给字符串长度,最后还是出题人在提问区补的,真的想打人。

后缀自动机裸题,大概就是以下这两题合在一起:

http://hihocoder.com/problemset/problem/1445

http://hihocoder.com/problemset/problem/1449

hihocoder上都有题解。

很裸,求一下endpos,再根据自动机性质,用maxlen(s) - minlen(s) + 1求出当前节点表示多少个子串,最后累加就可以了。

(357队会后缀自动机,这世界真可怕)

ac代码:

#include<bits/stdc++.h>
using namespace std;

const int maxn = 1e5 + 5;
typedef long long ll;
char s[maxn];

struct Sam {
	int next[maxn << 1][26];
	int link[maxn << 1], step[maxn << 1];
	ll endpos[maxn << 1];
	int a[maxn], b[maxn << 1];
	int sz, last, len;

	void init() {
		memset(next, 0, sizeof(next));
		memset(endpos, 0, sizeof(endpos));
		memset(a, 0, sizeof(a));
		memset(b, 0, sizeof(b));
		sz = last = 1;
	}

	void add(int c) {
		int p = last;
		int np = ++sz;
		last = np;

		endpos[np] = 1;
		step[np] = step[p] + 1;
		while(!next[p][c] && p) {
			next[p][c] = np;
			p = link[p];
		}

		if(p == 0) {
			link[np] = 1;
		} else {
			int q = next[p][c];
			if(step[p] + 1 == step[q]) {
				link[np] = q;
			} else {
				int clone = ++sz;
				memcpy(next[clone], next[q], sizeof(next[q]));
				step[clone] = step[p] + 1;
				link[clone] = link[q];
				link[q] = link[np] = clone;
				while(next[p][c] == q && p) {
					next[p][c] = clone;
					p = link[p];
				}
			}
		}
	}

	void build() {
		init();
		for(int i = 0; i < len; i++) {
			add(s[i] - 'A');
		}
		for(int i = 1; i <= sz; i++) {
			a[step[i]]++;
		}
		for(int i = 1; i <= len; i++) {
			a[i] += a[i - 1];
		}
		for(int i = 1; i <= sz; i++) {
			b[a[step[i]]--] = i;
		}
		for(int i = sz; i > 1; i--) {
			int e = b[i];
			endpos[link[e]] += endpos[e];
		}
	}

	void solve() {
		int A, B;
		scanf("%d%d", &A, &B);
		len = strlen(s);
		build();
		ll ans = 0;
		for(int i = 1; i <= sz; i++) {
			// printf("%d\n",endpos[i]);
			if(endpos[i] >= A && endpos[i] <= B) {
				ans += step[i] - step[link[i]];
			}
		}
		printf("%lld\n", ans);
	}

} sam;

// AABAA 1 9

int main() {
	while(~scanf("%s", s)) {
		sam.solve();
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Cymbals/article/details/82716712