• luogu3181 [HAOI2016]找相同字符串


    题目链接

    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;
    }
    
    
  • 相关阅读:
    wgcloud问题处理——被监控的客户机掉线
    WGCLOUD下发指令时候如何屏蔽linux敏感字符
    WGCLOUD左侧菜单如何保持展开状态
    zerotier 实现 minecraft 局域网联机 | 我的世界联机教程 | minecraft联机
    [ UVa 12096 详解] The Set Stack Computer 集合栈计算机 | map、set、vector、stack、宏函数等知识点简单应用
    [ Uva 101 详解 ] the block problem 木块问题
    Python操作数据库基本操作-sqlalchemy
    统计目录下程序源程序的行数之和-Python
    凯撒密码C++实现
    【题解】[AGC036F] Square Constraints
  • 原文地址:https://www.cnblogs.com/wxyww/p/luogu3181.html
Copyright © 2020-2023  润新知