【NOI2015】BZOJ4199品酒大会题解(SAM+树形DP)

版权声明:转载请注明原出处啦QAQ(虽然应该也没人转载): https://blog.csdn.net/hzk_cpp/article/details/88707133

题目:BZOJ4199.
题目大意:给定一个字符串 S S ,并给出一个长度为 S |S| 的序列 a i a_i .现在设 S i S_i 表示 S S 以第 i i 个字符开始的后缀,对于每个 0 r < S 0\leq r<|S| 要求 i = ̸ j i=\not{}j 使得 S i , S j S_i,S_j 的最长公共前缀LCP至少为 r r 的方案数和 a i a j a_i*a_j 最大的方案.
1 S 3 1 0 5 , a i 1 0 9 1\leq |S|\leq 3*10^5,|a_i|\leq 10^9 .

做这道题之前建议先去做做BZOJ3238差异.

首先可以转化为求每个 L C P LCP 恰好为 r r 的数量和最大值,最后后缀和,后缀最大值处理一下即可.

先考虑如何求数量.考虑两个串的LCP恰好为 r r 在后缀树上等价于两个点的LCA深度为 r r ,那么用直接在后缀树上树形DP即可.

然后考虑 a i a_i a j a_j 相乘的最大值.这个其实也不难,给每个表示后缀结尾的节点附上一个点权为它对应的 a i a_i ,也树形DP处理一遍就好了,不过注意需要有负数的情况,记一下最大值最小值就好了.

时间复杂度 O ( S Σ ) O(|S|\Sigma) .

代码如下:

#include<bits/stdc++.h> 
  using namespace std;
 
#define Abigail inline void
typedef long long LL;
 
const int N=300000,C=26,inf=(1<<30)-1;
const LL INF=(1LL<<61)-1;

int n;
LL a[N+9],cnt[N+9],ans[N+9];
char s[N+9];

struct automaton{
  int s[C],len,par;
}tr[N*2+9];
int cn,last,rght[N*2+9],mx[N*2+9],mn[N*2+9];

void Build_sam(){cn=last=1;}

void extend(int x){
  int np=++cn,p=last;
  tr[np].len=tr[p].len+1;rght[np]=1;mn[np]=mx[np]=a[n-tr[np].len+1];
  last=np;
  while (p&&!tr[p].s[x]) tr[p].s[x]=np,p=tr[p].par;
  if (!p) tr[np].par=1;
  else{
  	int q=tr[p].s[x];
  	if (tr[p].len+1==tr[q].len) tr[np].par=q;
  	else{
	  tr[++cn]=tr[q];tr[cn].len=tr[p].len+1;mx[cn]=-inf,mn[cn]=inf;
	  tr[np].par=tr[q].par=cn;
	  while (p&&tr[p].s[x]==q) tr[p].s[x]=cn,p=tr[p].par;
	}
  }
}

struct side{
  int y,next;
}e[N*2+9];
int lin[N*2+9],top;

void ins(int x,int y){
  e[++top].y=y;
  e[top].next=lin[x];
  lin[x]=top;
}

void Build_parent(){
  for (int i=2;i<=cn;++i)
    ins(tr[i].par,i);
}

LL trc[N*2+9],tra[N*2+9];

void dfs(int k){
  tra[k]=-INF;
  for (int i=lin[k];i;i=e[i].next){
  	dfs(e[i].y);
  	trc[k]+=(LL)rght[k]*rght[e[i].y];
  	if (!rght[e[i].y]) continue;
  	if (rght[k])
	  tra[k]=max(max(max((LL)mx[k]*mx[e[i].y],(LL)mn[k]*mn[e[i].y]),
	    max((LL)mx[k]*mn[e[i].y],(LL)mn[k]*mx[e[i].y])),tra[k]);
  	rght[k]+=rght[e[i].y];
    mx[k]=max(mx[k],mx[e[i].y]);
    mn[k]=min(mn[k],mn[e[i].y]);
  }
}

Abigail into(){
  scanf("%d",&n);
  scanf("%s",s+1);
  for (int i=1;i<=n;++i)
    scanf("%lld",&a[i]);
}

Abigail work(){
  Build_sam();
  for (int i=n;i>=1;--i)
    extend(s[i]-'a');
  Build_parent();
  dfs(1);
  for (int i=0;i<=n;++i) ans[i]=-INF;
  for (int i=1;i<=cn;++i)
    cnt[tr[i].len]+=trc[i],ans[tr[i].len]=max(ans[tr[i].len],tra[i]);
  for (int i=n-1;i>=0;--i)
    cnt[i]+=cnt[i+1],ans[i]=max(ans[i],ans[i+1]);
}

Abigail outo(){
  for (int i=0;i<n;++i)
    printf("%lld %lld\n",cnt[i],ans[i]==-INF?0:ans[i]);
}

int main(){
  into();
  work();
  outo();
  return 0;
}

猜你喜欢

转载自blog.csdn.net/hzk_cpp/article/details/88707133