[LOJ 2133][UOJ 131][BZOJ 4199][NOI 2015]品酒大会

题意

给定一个长度为 \(n\) 的字符串 \(s\), 对于所有 \(r\in[1,n]\) 求出 \(s\) 的所有LCP不小于 \(r\) 的后缀对的个数以及这些后缀对所能组成的最大权值.

一个后缀对 \((a,b)\) 的权值是它们左端点的权值的积.

\(n\le 3\times 10^5\).

题解

很久以前写的SAM沙雕题

因为要求LCP所以我们把这个串reverse一下用SAM搞.

根据后缀自动机的性质, 某两个后缀的LCP就是它们在SAM上对应结点的LCA的 \(len\).

那么对于计数的部分, 我们显然只要对于每个点都算出有多少个后缀以它为LCA就可以了.

后面求最大权值的部分看上去好像只要记录一下子树中的最大值和次大值就可以了, 然而权值可能有负数于是还得记录最小值和次小值.

计算出每个 \(len\) 的贡献后取后缀和就可以出答案了.

参考代码

#include <bits/stdc++.h>

const int MAXN=6e5+10;
typedef long long int64; struct Edge{
int from;
int to;
Edge* next;
};
Edge E[MAXN];
Edge* head[MAXN];
Edge* top=E; int n;
int cnt=1;
int root=1;
int last=1;
int v[MAXN];
char s[MAXN];
int len[MAXN];
int prt[MAXN];
int val[MAXN];
int size[MAXN];
int64 ans[MAXN];
int64 sum[MAXN];
int maxv[MAXN][2];
int minv[MAXN][2];
std::map<char,int> chd[MAXN]; void DFS(int);
void Insert(int,int);
void Extend(char,int); int main(){
memset(ans,0x80,sizeof(ans));
memset(maxv,0x80,sizeof(maxv));
memset(minv,0x7F,sizeof(minv));
scanf("%d",&n);
scanf("%s",s);
for(int i=0;i<n;i++)
scanf("%d",v+i);
for(int i=1;i<=n;i++)
Extend(s[n-i],v[n-i]);
for(int i=2;i<=cnt;i++)
Insert(prt[i],i);
DFS(root);
for(int i=n-1;i>=0;i--){
sum[i]+=sum[i+1];
ans[i]=std::max(ans[i],ans[i+1]);
}
for(int i=0;i<n;i++)
printf("%lld %lld\n",sum[i],sum[i]==0?0:ans[i]);
return 0;
} void UpdateMax(int x,int v){
maxv[x][1]=std::max(maxv[x][1],v);;
if(maxv[x][0]<maxv[x][1])
std::swap(maxv[x][0],maxv[x][1]);
} void UpdateMin(int x,int v){
minv[x][1]=std::min(minv[x][1],v);
if(minv[x][0]>minv[x][1])
std::swap(minv[x][0],minv[x][1]);
} void DFS(int root){
for(Edge* i=head[root];i!=NULL;i=i->next){
DFS(i->to);
sum[len[root]]+=1ll*size[root]*size[i->to];
size[root]+=size[i->to];
UpdateMin(root,minv[i->to][0]);
UpdateMin(root,minv[i->to][1]);
UpdateMax(root,maxv[i->to][0]);
UpdateMax(root,maxv[i->to][1]);
}
if(size[root]>1)
ans[len[root]]=std::max(ans[len[root]],std::max(1ll*minv[root][0]*minv[root][1],1ll*maxv[root][0]*maxv[root][1]));
} void Extend(char x,int v){
int p=last;
int np=++cnt;
size[last=np]=1;
len[np]=len[p]+1;
minv[np][0]=v;
maxv[np][0]=v;
while(p&&!chd[p].count(x))
chd[p][x]=np,p=prt[p];
if(p==0)
prt[np]=root;
else{
int q=chd[p][x];
if(len[q]==len[p]+1)
prt[np]=q;
else{
int nq=++cnt;
chd[nq]=chd[q];
prt[nq]=prt[q];
prt[q]=nq;
prt[np]=nq;
len[nq]=len[p]+1;
while(p&&chd[p][x]==q)
chd[p][x]=nq,p=prt[p];
}
}
} void Insert(int from,int to){
top->from=from;
top->to=to;
top->next=head[from];
head[from]=top++;
}

最新文章

  1. centos6.5 redmine 安装
  2. toolkit学习笔记
  3. java操作小技巧,遇到过的会一直更新,方便查找
  4. Catch That Cow(poj 3278)
  5. 纯C++文件调用MFC类
  6. jQuery修改后代、兄弟样式
  7. spring Integration服务总线
  8. JNI/NDK开发指南(开山篇)
  9. Android安装 sdk+jdk+Eclipse+Adt开发工具
  10. C/C++中define的使用
  11. 柯里化函数之Javascript
  12. 关于android中postDelayed方法的讲解
  13. asp.net Form 认证【转】
  14. Linux 下搭建jsp服务器(配置jsp开发环境)
  15. 使用boost::multi_index高速构建排行榜
  16. java的基础数据类型
  17. C# 多线程辅助类实现多任务
  18. windows环境用python修改环境变量的注意点(含代码)
  19. OpenGL(3)-三角形
  20. ccf消除类游戏

热门文章

  1. cartographer 3D scan matching 理解
  2. Apollo服务端设计原理剖析
  3. 还在担心网聊相亲的小姐姐,美女变恐龙!Python帮你&quot;潜伏&quot;侦查
  4. git分支合并创建切换
  5. 使用configparser模块进行封装,构造配置文件处理器
  6. 如何将Javaweb工程的访问协议由http改为https及通过域名访问?
  7. Mysql优化之Explain查询计划查看
  8. JS基础语法---函数练习part2---10个综合练习(运用:循环/数组/函数)
  9. 剑指offer 20:顺时针打印矩阵
  10. MySQL事务。