• luogu3804 【模板】后缀自动机


    题目链接

    solution

    用后缀数组水一发后缀自动机的模板233

    先跑一遍后缀数组,求出来height。然后根据height的性质,枚举造成贡献的位置,然后看一下这个位置在最长多长的一段区间内均为最小值。答案就是(len_i*height_i)(len_i)表示最长长度为(len_i)的一段区间(height)的最小值都是(height_i)。用单调栈统计即可。

    code

    /*
    * @Author: wxyww
    * @Date:   2020-04-20 07:58:21
    * @Last Modified time: 2020-04-20 08:36:41
    */
    #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 = 1000010;
    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;
    }
    char s[N];
    int sa[N],height[N],c[N],x[N],y[N],n,m;
    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) {
    			if(y[sa[i]] == y[sa[i - 1]] && y[sa[i] + k] == y[sa[i - 1] + k]) x[sa[i]] = num;
    			else x[sa[i]] = ++num;
    		}
    		m = num;
    		if(m == n) 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(j + k <= n && i + k <= n && s[j + k] == s[i + k]) ++k;
    		height[rk[i]] = k;
    		// printf("%d %d %d
    ",i,j,k);
    	}
    }
    int sta[N],top;
    int main() {
    	// freopen("P3804_1.in","r",stdin);
    	scanf("%s",s + 1);
    	n = strlen(s + 1);
    	m = 'z';
    	get_sa();
    
    	get_height();
    	// for(int i = 1;i <= n;++i) printf("%d ",height[i]);puts("");
    
    	int ans = 0;
    	for(int i = 1;i <= n + 1;++i) {
    		while(top && height[i] < height[sta[top]]) {
    			ans = max(ans,(i - sta[top - 1]) * height[sta[top]]);
    			--top;
    		}
    		sta[++top] = i;
    	}
    
    /*
    	for(int r = 1;r <= n;++r) {
    		int mn = height[r];
    		for(int l = r;l >= 1;--l) {
    			mn = min(mn,height[l]);
    			ans = max(ans,mn * (r - l + 2));
    		}
    	}*/
    
    	cout<<ans;
    	return 0;
    }
    
  • 相关阅读:
    Android Studio快速查看apk的MD5、SHA1、SHA256
    aapt remove 命令报 error during crunch archive is toast
    如何快速将MySQL数据库转换为PostgreSQL数据库
    Exception in thread “main“ org.apache.xmlbeans.impl.values.XmlValueDisconnectedException
    idea2021奇葩问题:找不到程序包和符号
    Unable to find method ‘org.gradle.api.tasks.TaskInputs.property
    laravel response返回值精度问题
    中缀、前缀、后缀表达式的运算
    选择排序
    中缀表达式转后缀表达式
  • 原文地址:https://www.cnblogs.com/wxyww/p/luogu3804.html
Copyright © 2020-2023  润新知