ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

luogu3181 [HAOI2016]找相同字符串

2020-04-20 19:52:03  阅读:255  来源: 互联网

标签:get int top height HAOI2016 luogu3181 字符串 sa include


题目链接

solution

用后缀数组来处理。将两个字符串拼接到一起,然后跑一边后缀数组。

后面的如果暴力做的话,就是枚举一下相同字符串的起始位置,然后用\(height\)数组求一下这两个后缀的\(LCP\),答案加上\(LCP\)就行了。

然后考虑优化,枚举贡献,也就是枚举一个\(height_i\)找到以\(height_i\)为最小值的最长区间,该区间\(i\)两端分属两个字符串的位置都会两两产生贡献。找这个区间可以通过单调栈解决。然后就是统计贡献,只要分别于处理一下两个数组的前缀和就能统计这个区间内某个位置两端的分属两个字符串的对数。

code

/*
* @Author: wxyww
* @Date:   2020-04-20 18:55:57
* @Last Modified time: 2020-04-20 19:30:57
*/
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
#include<ctime>
using namespace std;
typedef long long ll;
const int N = 400010;
ll read() {
	ll x = 0,f = 1;char c = getchar();
	while(c < '0' || c > '9') {
		if(c == '-') f = -1; c = getchar();
	}
	while(c >= '0' && c <= '9') {
		x = x * 10 + c - '0'; c = getchar();
	}
	return x * f;
}
int x[N],m,sa[N],height[N],y[N],c[N],n,bel[N];
char s[N],s1[N],s2[N];
void get_sa() {
	for(int i = 1;i <= n;++i) ++c[x[i] = s[i]];
	for(int i = 1;i <= m;++i) c[i] += c[i - 1];
	for(int i = n;i >= 1;--i) sa[c[x[i]]--] = i;
	for(int k = 1;k <= n;k <<= 1) {
		int num = 0;
		for(int i = n - k + 1;i <= n;++i) y[++num] = i;
		for(int i = 1;i <= n;++i) if(sa[i] > k) y[++num] = sa[i] - k;
		for(int i = 1;i <= m;++i) c[i] = 0;
		for(int i = 1;i <= n;++i) ++c[x[i]];
		for(int i = 1;i <= m;++i) c[i] += c[i - 1];
		for(int i = n;i >= 1;--i) sa[c[x[y[i]]]--] = y[i];
		swap(x,y);
		num = 0;
		x[sa[1]] = ++num;
		for(int i = 2;i <= n;++i) 
			x[sa[i]] = (y[sa[i - 1]] == y[sa[i]] && y[sa[i - 1] + k] == y[sa[i] + k]) ? num : ++num;
		m = num;
		if(n == m) break;
	}
}
int rk[N];
void get_height() {
	for(int i = 1;i <= n;++i) rk[sa[i]] = i;
	int k = 0;
	for(int i = 1;i <= n;++i) {
		if(rk[i] == 1) continue;
		if(k) --k;
		int j = sa[rk[i] - 1];
		while(i + k <= n && j + k <= n && s[i + k] == s[j + k]) ++k;
		height[rk[i]] = k;
	}
}
int sta[N],top,sum[3][N];
int get(int x,int l,int r) {
	return sum[x][r] - sum[x][max(0,l - 1)];
}
int main() {
	// freopen("1.in","r",stdin);
	scanf("%s",s1 + 1);
	scanf("%s",s2 + 1);
	for(int i = 1;s1[i];++i) {
		s[++n] = s1[i];
		bel[n] = 1;
	}

	s[++n] = '#';
	for(int i = 1;s2[i];++i) {
		s[++n] = s2[i];
		bel[n] = 2;
	}

	// printf("%s",s + 1);puts("");

	m = 'z';
	get_sa();

	// for(int i = 1;i <= n;++i) printf("%d ",sa[i]);puts("");

	get_height();

	// for(int i = 1;i <= n;++i) printf("%d ",height[i]);puts("");
	for(int i = 1;i <= n;++i) {
		sum[1][i] = sum[1][i - 1];
		sum[2][i] = sum[2][i - 1];
		sum[bel[sa[i]]][i]++;
	}
	ll ans = 0 ;
	for(int i = 1;i <= n + 1;++i) {
		while(top && height[sta[top]] > height[i]) {
			int j = sta[top - 1],k = sta[top];
			ans += 1ll * get(1,j,k - 1) * get(2,k,i - 1) * height[k];
			ans += 1ll * get(2,j,k - 1) * get(1,k,i - 1) * height[k];
			--top;
		}
		sta[++top] = i;
	}
	cout<<ans;


	return 0;
}

标签:get,int,top,height,HAOI2016,luogu3181,字符串,sa,include
来源: https://www.cnblogs.com/wxyww/p/luogu3181.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有