BZOJ

洛谷

后缀数组做法

洛谷上SAM比SA慢...BZOJ SAM却能快近一倍...

只考虑求极长相同子串,即所有后缀之间的LCP。

而后缀的LCP在后缀树的LCA处。同差异这道题,在每个点处树形DP统计它作为LCA时的贡献即可(有多少对后缀以它为LCA)。

而第二问,同样维护子树内的最大值次大值、最小值次小值作为答案即可。

非后缀节点的\(size=0\),最值的初值同样要设成\(INF\)...但是最后也要一样DP。

初始设成\(INF\)在最后转移的时候同样要判...(不能是两个\(INF\)相乘)不妨直接只在\(size\geq2\)的时候DFS/更新答案。

//95648kb	2744ms
#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
#define gc() getchar()
typedef long long LL;
const int N=3e5+5,INF=1<<30; //char OUT[8000000],*O=OUT;//7e6 isn't enough...
inline int read()
{
int now=0,f=1;register char c=gc();
for(;!isdigit(c);c=='-'&&(f=-1),c=gc());
for(;isdigit(c);now=now*10+c-'0',c=gc());
return now*f;
}
//inline void print(LL x)
//{
// static char obuf[20];
// if(x<0) x=-x, *O++='-';
// if(x)
// {
// int t=0; while(x) obuf[++t]=x%10+48, x/=10;
// while(t) *O++=obuf[t--];
// }
// else *O++='0';
//} struct Suffix_Automaton
{
#define S N<<1
int las,tot,son[S][26],len[S],fa[S],tm[S],A[S],sz[S],mx1[S],mx2[S],mn1[S],mn2[S];
LL sum[N],Ans[N];
char s[N];
#undef S
void Insert(int c,int v)
{
int p=las,np=++tot;
len[las=np]=len[p]+1, sz[np]=1;
mx1[np]=mn1[np]=v, mx2[np]=-INF, mn2[np]=INF;
for(; p&&!son[p][c]; p=fa[p]) son[p][c]=np;
if(!p) fa[np]=1;
else
{
int q=son[p][c];
if(len[q]==len[p]+1) fa[np]=q;
else
{
int nq=++tot; len[nq]=len[p]+1;
mx1[nq]=mx2[nq]=-INF, mn1[nq]=mn2[nq]=INF;
memcpy(son[nq],son[q],sizeof son[q]);
fa[nq]=fa[q], fa[q]=fa[np]=nq;
for(; son[p][c]==q; p=fa[p]) son[p][c]=nq;
}
}
}
void Solve(const int n)
{
las=tot=1, scanf("%s",s+1);
for(int i=1; i<=n; ++i) A[i]=read();
for(int i=n; i; --i) Insert(s[i]-'a',A[i]); for(int i=1; i<=tot; ++i) ++tm[len[i]];
for(int i=1; i<=n; ++i) tm[i]+=tm[i-1];
for(int i=tot; i; --i) A[tm[len[i]]--]=i; for(int i=tot,v=A[i],x,l; i; v=A[--i])
{
x=fa[v], l=len[x];
sum[l]+=1ll*sz[x]*sz[v], sz[x]+=sz[v];
mx1[v]>mx1[x]?(mx2[x]=mx1[x],mx1[x]=mx1[v]):(mx2[x]=std::max(mx2[x],mx1[v]));
mx2[x]=std::max(mx2[x],mx2[v]);
mn1[v]<mn1[x]?(mn2[x]=mn1[x],mn1[x]=mn1[v]):(mn2[x]=std::min(mn2[x],mn1[v]));
mn2[x]=std::min(mn2[x],mn2[v]);
}
memset(Ans,-0x3f,sizeof Ans);
for(int x=1; x<=tot; ++x)
sz[x]>=2 && (Ans[len[x]]=std::max(Ans[len[x]],std::max(1ll*mx1[x]*mx2[x],1ll*mn1[x]*mn2[x]))); for(int i=n-1; ~i; --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]?Ans[i]:0);
// for(int i=0; i<n; ++i) print(sum[i]),*O++=' ',print(sum[i]?Ans[i]:0),*O++='\n';
// fwrite(OUT,1,O-OUT,stdout);
}
}sam; int main()
{
sam.Solve(read());
return 0;
}

BZOJ.4199.[NOI2015]品酒大会(后缀自动机 树形DP)的更多相关文章

  1. BZOJ 4199: [Noi2015]品酒大会 后缀自动机_逆序更新

    一道裸题,可以考虑自底向上去更新方案数与最大值. 没啥难的 细节........ Code: #include <cstdio> #include <algorithm> #i ...

  2. BZOJ 4199: [Noi2015]品酒大会 [后缀数组 带权并查集]

    4199: [Noi2015]品酒大会 UOJ:http://uoj.ac/problem/131 一年一度的“幻影阁夏日品酒大会”隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发“首席品 ...

  3. BZOJ.4199.[NOI2015]品酒大会(后缀数组 单调栈)

    BZOJ 洛谷 后缀自动机做法. 洛谷上SAM比SA慢...BZOJ SAM却能快近一倍... 显然只需要考虑极长的相同子串的贡献,然后求后缀和/后缀\(\max\)就可以了. 对于相同子串,我们能想 ...

  4. BZOJ 4199: [Noi2015]品酒大会( 后缀数组 + 并查集 )

    求出后缀数组后, 对height排序, 从大到小来处理(r相似必定是0~r-1相似), 并查集维护. 复杂度O(NlogN + Nalpha(N)) ------------------------- ...

  5. bzoj 4199: [Noi2015]品酒大会 后缀树

    题目大意: 给定一个长为n的字符串,每个下标有一个权\(w_i\),定义下标\(i,j\)是r相似的仅当\(r \leq LCP(suf(i),suf(j))\)且这个相似的权为\(w_i,w_j\) ...

  6. uoj 131/bzoj 4199 [NOI2015]品酒大会 后缀树+树d

    题目大意 见uoj131 分析 题目的提示还是很明显的 \(r\)相似就就代表了\(0...r-1\)相似 建出后缀树我们能dfs算出答案 再后缀和更新一下即可 注意 细节挺多的,但数据很良心 不然我 ...

  7. 【BZOJ 4199】[Noi2015]品酒大会 后缀自动机+DP

    题意 两个长度为$r$的子串相等称为$r$相似,两个$r$相似的权值等于子串开头位置权值乘积,给定字符串和每个位置权值,求$r$相似子串数量和最大权值乘积 对反串建立后缀自动机得到后缀树,后缀树上两个 ...

  8. 【bzoj4199】[Noi2015]品酒大会 后缀自动机求后缀树+树形dp

    题目描述(转自百度文库) 一年一度的“幻影阁夏日品酒大会”隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发“首席品酒家”和“首席猎手”两个奖项,吸引了众多品酒师参加. 在大会的晚餐上,调酒 ...

  9. bzoj 4199: [Noi2015]品酒大会

    Description 一年一度的"幻影阁夏日品酒大会"隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发"首席品酒家"和"首席猎手&quo ...

随机推荐

  1. poj3107树的重心

    /*树的重心求法:两次dfs,第一次dfs处理出每个结点的size,以此求每个结点大儿子的size,第二次dfs将每个结点大儿子的size和余下结点数进行比较,所有结点里两个值之间差值最小的那个点就是 ...

  2. java常用的中间件

    tomcatWeblogicJBOSSColdfusionWebsphereGlassFish 一般本地开发的话建议使用tomcat. linux系统建议使用jetty或apache hpptd 大型 ...

  3. linux学习笔记之 basename, dirname

    前言: basename: 用于打印目录或者文件的基本名称 dirname: 去除文件名中的非目录部分,仅显示与目录有关的内容.dirname命令读取指定路径名保留最后一个/及其后面的字符,删除其他部 ...

  4. 饮冰三年-人工智能-linux-04 vim编辑器

    vim的三种模式:命令行模式.编辑模式.扩展模式 1:命令行模式下常见的操作 删除 a):dd 删除光标所在当前行 b):ndd   删除光标所在当前行后的n行 复制 c):yy 复制光标所在当前行 ...

  5. 复习reactnative....

    import React, { Component } from 'react'; import { AppRegistry, Text, Image, View, TextInput, Scroll ...

  6. Mac Mojave(10.14.1)执行Matlab的mex报错

    先装了matlab2018b,发现很频繁的crash,同时考虑到要跑的代码在>=2017a时就计算错误,于是转战matlab2016b matlab2016b安装后,执行mex -setup报错 ...

  7. Knockout示例:User数据CRUD

    模拟数据user.json. { "page": 0, "rows": 0, "total": 161, "isSuccess&q ...

  8. luogu 1471

    题意: 蒟蒻HansBug在一本数学书里面发现了一个神奇的数列,包含N个实数.他想算算这个数列的平均数和方差. 操作1:1 x y k ,表示将第x到第y项每项加上k,k为一实数. 操作2:2 x y ...

  9. python全栈开发day57- pymysql、视图、触发器、函数

    一.昨日内容回顾 1.单表查询 优先级 from where group by having select distinct order by limit 2 . 多表查询 inner join... ...

  10. Python_列表常用操作

    %d   数字 %f    浮点 %s    字符串 字符串常用功能: .strip()   默认去掉字符串两边空格#或者在括号里注明去除什么 查看列表方法:dir(列表名) .append(元素): ...