zoukankan      html  css  js  c++  java
  • [洛谷P3804]【模板】后缀自动机

    题目大意:给一个只包含小写字母的字符串 $S$ ,请求出 $S$ 的所有出现次数不为 $1$ 的子串的出现次数乘上该子串长度的最大值。

    题解:用后缀自动机求出每个字串的长度,排序后求出字串出现次数(后缀自动机是背板的。。。)

    卡点:1.$rnk$数组没有开两倍

      板背错

    C++ Code:

    #include <cstdio>
    #include <cstring>
    #define maxn 1000010
    using namespace std;
    char s[maxn << 1];
    int nxt[maxn << 1][26], fail[maxn << 1], R[maxn << 1];
    int sz[maxn << 1];
    int b[maxn], rnk[maxn << 1];
    int root, np, p, cnt, t, last, len;
    long long ans = -1;
    inline long long max(long long a, long long b) {return a > b ? a : b;}
    void insert(int ch) {
    	int now = ++cnt, np;
    	R[now] = R[p = last] + 1;
    	sz[now] = 1; last = now;
    	for (; ~p && !nxt[p][ch]; p = fail[p]) nxt[p][ch] = now;
    	if (!~p) {fail[now] = root; return ;}
    	if (R[t = nxt[p][ch]] == R[p] + 1) {fail[now] = t; return ;}
    	R[np = ++cnt] = R[p] + 1;
    	for (int i = 0; i < 26; i++) nxt[np][i] = nxt[t][i];
    	for (fail[np] = fail[t], fail[t] = fail[now] = np; nxt[p][ch] == t; p = fail[p]) nxt[p][ch] = np;
    }
    int main() {
    	scanf("%s", s);
    	len = strlen(s);
    	fail[root = 0] = -1; cnt = last = 1;
    	for (int i = 0; i < len; i++) insert(s[i] - 'a');
    	for (int i = 1; i <= cnt; i++) b[R[i]]++;
    	for (int i = 1; i <= len; i++) b[i] += b[i - 1];
    	for (int i = 1; i <= cnt; i++) rnk[b[R[i]]--] = i;
    	for (int i = cnt; i; i--) {
    		int now = rnk[i];
    		sz[fail[now]] += sz[now];
    		if (sz[now] > 1) ans = max(ans, 1ll * sz[now] * R[now]);
    	}
    	printf("%lld
    ", ans);
    	return 0;
    } 
    

      

  • 相关阅读:
    网易2019实习生招聘编程第3题——牛牛找工作
    Linux find、locate、whereis、which命令
    Linux 常用命令
    Java线程池
    java连接池的maxIdle该如何配置
    Idea和redis的坑
    微服务架构下分布式事务解决方案——阿里GTS
    spring管理bean的三种创建方式
    jvm内存过高及那些对象导致内存过高,那些对象不会被gc回收
    Java虚拟机 运行时数据区
  • 原文地址:https://www.cnblogs.com/Memory-of-winter/p/9446696.html
Copyright © 2011-2022 走看看