• 【刷题】洛谷 P3804 【模板】后缀自动机


    题目描述

    给定一个只包含小写字母的字符串 (S) ,

    请你求出 (S) 的所有出现次数不为 (1) 的子串的出现次数乘上该子串长度的最大值。

    输入输出格式

    输入格式:

    一行一个仅包含小写字母的字符串 (S)

    输出格式:

    一个整数,为所求答案

    输入输出样例

    输入样例#1:

    abab
    

    输出样例#1:

    4
    

    说明

    对于 (10\%) 的数据, (|S| leq 1000)

    对于 (100\%) 的数据,(|S| leq 10^6)

    题解

    SAM模板题

    建出SAM后,统计子树和算每个状态最长子串的出现次数,根据贪心,由于题目求的是同一个子串的出现次数和长度的乘积,所以在同一个状态的子串,出现次数相同,那么只要选最长的就行了

    于是基数排序搞出拓扑序,统计一下就好了

    #include<bits/stdc++.h>
    #define ui unsigned int
    #define ll long long
    #define db double
    #define ld long double
    #define ull unsigned long long
    const int MAXN=1000000+10;
    int n,las=1,tot=1,len[MAXN<<1],ch[MAXN<<1][30],fa[MAXN<<1],cnt[MAXN],rk[MAXN<<1],size[MAXN<<1];
    ll ans;
    char s[MAXN];
    template<typename T> inline void read(T &x)
    {
    	T data=0,w=1;
    	char ch=0;
    	while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    	if(ch=='-')w=-1,ch=getchar();
    	while(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar();
    	x=data*w;
    }
    template<typename T> inline void write(T x,char ch='')
    {
    	if(x<0)putchar('-'),x=-x;
    	if(x>9)write(x/10);
    	putchar(x%10+'0');
    	if(ch!='')putchar(ch);
    }
    template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);}
    template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);}
    template<typename T> inline T min(T x,T y){return x<y?x:y;}
    template<typename T> inline T max(T x,T y){return x>y?x:y;}
    inline void extend(int c)
    {
    	int p=las,np=++tot;
    	las=np;
    	len[np]=len[p]+1;
    	while(p&&!ch[p][c])ch[p][c]=np,p=fa[p];
    	if(!p)fa[np]=1;
    	else
    	{
    		int q=ch[p][c];
    		if(len[q]==len[p]+1)fa[np]=q;
    		else
    		{
    			int nq=++tot;
    			fa[nq]=fa[q];
    			memcpy(ch[nq],ch[q],sizeof(ch[nq]));
    			len[nq]=len[p]+1,fa[q]=fa[np]=nq;
    			while(p&&ch[p][c]==q)ch[p][c]=nq,p=fa[p];
    		}
    	}
    	size[np]=1;
    }
    int main()
    {
    	scanf("%s",s+1);
    	n=strlen(s+1);
    	for(register int i=1;i<=n;++i)extend(s[i]-'a'+1);
    	for(register int i=1;i<=tot;++i)cnt[len[i]]++;
    	for(register int i=1;i<=n;++i)cnt[i]+=cnt[i-1];
    	for(register int i=1;i<=tot;++i)rk[cnt[len[i]]--]=i;
    	for(register int i=tot;i>=1;--i)
    	{
    		size[fa[rk[i]]]+=size[rk[i]];
    		if(size[rk[i]]>1)chkmax(ans,1ll*size[rk[i]]*len[rk[i]]);
    	}
    	write(ans,'
    ');
    	return 0;
    }
    
  • 相关阅读:
    mac 终端 常用命令
    创办支持多种屏幕尺寸的Android应用
    java学习之部分笔记2
    java学习之部分笔记
    java学习之i/o
    java中String的用法
    java中List的用法
    java学习之Date的使用
    java学习之数据库
    C#中通过类来继承两个接口,父类实例化接口中的方法,子类继承父类,调用方法
  • 原文地址:https://www.cnblogs.com/hongyj/p/9100587.html
Copyright © 2020-2023  润新知