zoukankan      html  css  js  c++  java
  • LOJ

    题目

    传送门

    解法

    首先有个结论:后缀自动机的 ( ext{parent tree}) 就是其反串的 后缀树(概述图比较清晰)。前者的父子关系基于后缀,后者的父子关系基于前缀。那么反过来,我们建反串的后缀自动机,其 ( ext{parent tree}) 就是原串的后缀树。

    现在建出原串的后缀树(它的用途待会再讲)。由于后缀自动机是增量构造,且每次新出现的整串都会创立新的等价类,这又恰好出现了新的字符(也就是出现了新的位置),所以每次新出现的整串所代表的节点一定能包含序列中 每个字符开始的字符串,而且新的字符就是那个 开始(如果是原串的后缀自动机这个开始即串尾)。这样原串的后缀树相当从后往前插入,我们已知新的字符就是串首,方便我们插入权值。

    注意,能贡献的只有每次新出现的整串创立的等价类。

    由于两个前缀的最长公共后缀长度可以看做 ( ext{parent tree}) 上两个节点的 ( ext{LCA})len,我们遍历子树 (u) 时,就将它的子树分别计算贡献至 Kind[len]。而美味值因为有负数,需要维护最大值和最小值。

    最后,由于计算的是正好长度为 (r) 的串,需要再做一个后缀和/求最大值。

    代码

    #include <cstdio>
    
    #define rep(i,_l,_r) for(register signed i=(_l),_end=(_r);i<=_end;++i)
    #define fep(i,_l,_r) for(register signed i=(_l),_end=(_r);i>=_end;--i)
    #define erep(i,u) for(signed i=head[u],v=to[i];i;i=nxt[i],v=to[i])
    #define efep(i,u) for(signed i=Head[u],v=to[i];i;i=nxt[i],v=to[i])
    #define print(x,y) write(x),putchar(y)
    
    template <class T> inline T read(const T sample) {
        T x=0; int f=1; char s;
        while((s=getchar())>'9'||s<'0') if(s=='-') f=-1;
        while(s>='0'&&s<='9') x=(x<<1)+(x<<3)+(s^48),s=getchar();
        return x*f;
    }
    template <class T> inline void write(const T x) {
        if(x<0) return (void) (putchar('-'),write(-x));
        if(x>9) write(x/10);
        putchar(x%10^48);
    }
    template <class T> inline T Max(const T x,const T y) {if(x>y) return x; return y;}
    template <class T> inline T Min(const T x,const T y) {if(x<y) return x; return y;}
    template <class T> inline T fab(const T x) {return x>0?x:-x;}
    template <class T> inline T gcd(const T x,const T y) {return y?gcd(y,x%y):x;}
    template <class T> inline T lcm(const T x,const T y) {return x/gcd(x,y)*y;}
    template <class T> inline T Swap(T &x,T &y) {x^=y^=x^=y;}
    
    #include <vector>
    #include <cstring>
    using namespace std;
    typedef long long ll;
    
    const int maxn=3e5+5;
    
    int n,a[maxn],maxx[maxn<<1],minn[maxn<<1];
    char str[maxn];
    vector <int> e[maxn<<1];
    ll Kind[maxn<<1],Yummy[maxn<<1];
    struct SAM {
    	int cnt,las;
    	int siz[maxn<<1];
    	struct node {
    		int fa,to[26],len;
    	} s[maxn<<1];
    	
    	SAM() {las=cnt=1;}
    	
    	void Extend(int i) {
    		int cur=++cnt,p=las,c=str[i]-'a'; s[cur].len=s[las].len+1;
    		siz[cur]=1; maxx[cur]=minn[cur]=a[i];
    		for(;p && s[p].to[c]==0;p=s[p].fa) s[p].to[c]=cur;
    		if(!p) s[cur].fa=1;
    		else {
    			int q=s[p].to[c];
    			if(s[q].len==s[p].len+1) s[cur].fa=q;
    			else {
    				int now=++cnt; s[now]=s[q];
    				s[now].len=s[p].len+1;
    				s[q].fa=s[cur].fa=now;
    				for(;p && s[p].to[c]==q;p=s[p].fa) s[p].to[c]=now;
    			}
    		}
    		las=cur;
    	}
    	
    	void Link() {
    		rep(i,2,cnt) e[s[i].fa].push_back(i);
    	}
    	
    	void dfs(int u) {
    		for(int i=0;i<e[u].size();++i) {
    			int v=e[u][i];
    			dfs(v);
    			Kind[s[u].len]+=1ll*siz[u]*siz[v];
    			siz[u]+=siz[v];
    			if((maxx[u]^maxx[0]) && (maxx[v]^maxx[0])) Yummy[s[u].len]=Max(Yummy[s[u].len],1ll*maxx[u]*maxx[v]);
    			if((minn[u]^minn[0]) && (minn[v]^minn[0])) Yummy[s[u].len]=Max(Yummy[s[u].len],1ll*minn[u]*minn[v]);
    			maxx[u]=Max(maxx[u],maxx[v]),minn[u]=Min(minn[u],minn[v]);
    		}
    	}
    } mac;
    
    int main() {
    	memset(maxx,0x80,sizeof maxx);
    	memset(Yummy,0x80,sizeof Yummy);
    	memset(minn,0x3f,sizeof minn);
    	n=read(9),scanf("%s",str+1);
    	rep(i,1,n) a[i]=read(9);
    	fep(i,n,1) mac.Extend(i);
    	mac.Link(),mac.dfs(1);
    	fep(i,n-2,0) Kind[i]+=Kind[i+1],Yummy[i]=Max(Yummy[i+1],Yummy[i]);
    	rep(i,0,n-1)
    		if(Kind[i]) print(Kind[i],' '),print(Yummy[i],'
    ');
    		else puts("0 0");
    	return 0;
    }
    
  • 相关阅读:
    解决Java版CKFinder无法显示缩略图问题
    python视频教程大全
    关于Linux vi命令 vi命令一览表
    Python快速教程
    Linux的概念与体系
    每天一个linux命令目录
    每天一个linux命令(31): /etc/group文件详解
    每天一个linux命令(30): chown命令
    每天一个linux命令(29):chgrp命令
    十大Material Design开源项目
  • 原文地址:https://www.cnblogs.com/AWhiteWall/p/14423143.html
Copyright © 2011-2022 走看看