题目

传送门

解法

首先将查询 \(\text{lcp}(u,v)\ge r\) 改成 \(\text{lcp}(u,v)= r\),最后算一个后缀和、后缀积即可。

我们知道,在后缀自动机上的两个后缀的最大共同后缀就是 \(\text{len}(\text{lca}(u,v))\)(在 \(\text{parent tree}\) 上)。由于这题要求 \(\rm lcp\),所以将串倒过来插入。注意,能贡献的只有每次新出现的整串创立的等价类!所以后缀自动机的 \(\rm node\) 最好不要包含维护的 \(\mathtt{dp}\) 值,这样不好 \(\rm copy\).

然后在 \(\text{parent tree}\) 上大力 \(\mathtt{dp}\) 即可。由于美味值有负数,需要维护最大值和最小值。

代码

#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],'\n');
		else puts("0 0");
	return 0;
}
posted on 2021-02-20 20:23  Oxide  阅读(36)  评论(0编辑  收藏  举报