题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=4199

题意:

  给你一个长度为n的字符串s,和一个长为n的数组v。

  对于每个整数r∈[0,n-1]:

    (1)问你有多少对后缀(suffix(i), suffix(j)),满足LCP(suffix(i), suffix(j)) >= r

    (2)输出mul[r] = max(v[i]*v[j]),其中i,j满足(1)的条件

题解:

  先考虑第(1)问。

  由于LCP只受连续的一段height中最小值的影响

  所以先将height数组排序,然后按height从大到小的顺序,合并当前height对应的两个后缀suffix(i)和suffix(j)所在的集合。

  那么对于任意两个分别属于这两个集合的后缀来说,它们的LCP一定为当前height。

  假设ans[r]表示LCP恰好为r的后缀对个数,那么此时的贡献为ans[height] += siz[find(i)] * siz[find(j)]

  最后对ans数组求一遍后缀和,即为LCP >= r的后缀对个数。

  然后再考虑第(2)问。

  由于v[i]有可能为负值,所以对于每个集合,维护集合中元素对应v[i]的最大值和最小值。

  那么每次合并时,用max(两个集合的最大值之积,最小值之积)更新mul[par]即可。

AC Code:

 #include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define MAX_N 300005 using namespace std; struct Height
{
int v,id;
Height(int _v,int _id)
{
v=_v; id=_id;
}
Height(){}
friend bool operator < (const Height &a,const Height &b)
{
return a.v<b.v;
}
}; int n;
int a[MAX_N];
int sa[MAX_N];
int rk[MAX_N];
int t1[MAX_N];
int t2[MAX_N];
int cnt[MAX_N];
int tsa[MAX_N];
int height[MAX_N];
int par[MAX_N];
long long siz[MAX_N];
long long maxn[MAX_N];
long long minn[MAX_N];
long long v[MAX_N];
long long ans[MAX_N];
long long mul[MAX_N];
char s[MAX_N];
Height h[MAX_N]; void rsort()
{
memset(cnt,,sizeof(cnt));
for(int i=;i<=n;i++) cnt[t2[i]]++;
for(int i=;i<=n;i++) cnt[i]+=cnt[i-];
for(int i=n;i>=;i--) tsa[cnt[t2[i]]--]=i;
memset(cnt,,sizeof(cnt));
for(int i=;i<=n;i++) cnt[t1[i]]++;
for(int i=;i<=n;i++) cnt[i]+=cnt[i-];
for(int i=n;i>=;i--) sa[cnt[t1[tsa[i]]]--]=tsa[i];
} void suffix()
{
memset(cnt,,sizeof(cnt));
for(int i=;i<=n;i++) a[i]=s[i],cnt[a[i]]++;
for(int i='a';i<='z';i++) cnt[i]+=cnt[i-];
for(int i=;i<=n;i++) rk[i]=cnt[a[i]];
int len=;
while(len<n)
{
for(int i=;i<=n;i++)
{
t1[i]=rk[i];
t2[i]=i+len<=n ? rk[i+len] : ;
}
rsort();
for(int i=;i<=n;i++)
{
rk[sa[i]]=rk[sa[i-]]+(t1[sa[i]]!=t1[sa[i-]] || t2[sa[i]]!=t2[sa[i-]]);
}
len<<=;
}
int k=;
for(int i=;i<=n;i++)
{
k=k?k-:k;
int j=sa[rk[i]-];
while(a[i+k]==a[j+k]) k++;
height[rk[i]]=k;
}
} void init_union_find()
{
for(int i=;i<=n;i++)
{
par[i]=i;
siz[i]=;
maxn[i]=minn[i]=v[i];
}
} int find(int x)
{
return par[x]==x ? x : par[x]=find(par[x]);
} void unite(int x,int y,int r)
{
int px=find(x);
int py=find(y);
ans[r]+=siz[px]*siz[py];
mul[r]=max(mul[r],max(maxn[px]*maxn[py],minn[px]*minn[py]));
siz[py]+=siz[px];
maxn[py]=max(maxn[py],maxn[px]);
minn[py]=min(minn[py],minn[px]);
par[px]=py;
} void read()
{
scanf("%d%s",&n,s+);
for(int i=;i<=n;i++) scanf("%lld",&v[i]);
} void work()
{
suffix();
init_union_find();
for(int i=;i<=n;i++) h[i]=Height(height[i],i);
sort(h+,h++n);
memset(ans,,sizeof(ans));
memset(mul,0x80,sizeof(mul));
for(int i=n;i>=;i--) unite(sa[h[i].id],sa[h[i].id-],h[i].v);
for(int i=n-;i>=;i--) ans[i]+=ans[i+],mul[i]=max(mul[i],mul[i+]);
for(int i=;i<n;i++)
{
if(ans[i]) printf("%lld %lld\n",ans[i],mul[i]);
else printf("0 0\n");
}
} int main()
{
read();
work();
}

BZOJ 4199 [Noi2015]品酒大会:后缀数组 + 并查集的更多相关文章

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

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

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

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

  3. [UOJ#131][BZOJ4199][NOI2015]品酒大会 后缀数组 + 并查集

    [UOJ#131][BZOJ4199][NOI2015]品酒大会 试题描述 一年一度的“幻影阁夏日品酒大会”隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发“首席品酒家”和“首席猎手”两个 ...

  4. 【BZOJ4199】[Noi2015]品酒大会 后缀数组+并查集

    [BZOJ4199][Noi2015]品酒大会 题面:http://www.lydsy.com/JudgeOnline/wttl/thread.php?tid=2144 题解:听说能用SAM?SA默默 ...

  5. [NOI2015] 品酒大会 - 后缀数组,并查集,STL,启发式合并

    [NOI2015] 品酒大会 Description 对于每一个 \(i \in [0,n)\) 求有多少对后缀满足 LCP 长度 \(\le i\) ,并求满足条件的两个后缀权值乘积的最大值. So ...

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

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

  7. 【学术篇】NOI2015 品酒大会 后缀数组+并查集

    省选前大致是刷不了几道题了... 所以就找一些裸一点的题目练练板子算了= = 然而这题一点都不裸, 也并不怎么好写... 于是就浪费了将近一下午的时间... 然而还不是因为后缀数组板子不熟= = 首先 ...

  8. NOI 2015 品酒大会 (后缀数组+并查集)

    题目大意:略 40分暴力还是很好写的,差分再跑个后缀和 和 后缀最大值就行了 一种正解是后缀数组+并查集 但据说还有后缀数组+单调栈的高端操作蒟蒻的我当然不会 后缀数组求出height,然后从大到小排 ...

  9. BZOJ.4199.[NOI2015]品酒大会(后缀自动机 树形DP)

    BZOJ 洛谷 后缀数组做法. 洛谷上SAM比SA慢...BZOJ SAM却能快近一倍... 只考虑求极长相同子串,即所有后缀之间的LCP. 而后缀的LCP在后缀树的LCA处.同差异这道题,在每个点处 ...

  10. Uoj #131. 【NOI2015】品酒大会 后缀数组,并查集

    #131. [NOI2015]品酒大会 统计 描述 提交 自定义测试 一年一度的“幻影阁夏日品酒大会”隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发“首席品酒家”和“首席猎手”两个奖项, ...

随机推荐

  1. 启动 ./spark-shell 命令报错

    当使用./spark-shell 命令报错 Caused by: ERROR XJ040: Failed to start database @476fde05, see the next excep ...

  2. SpringBoot项目的云服务器部署

    1.场景还原 springboot配置相当简单,人人皆知.怎么把springboot工程部署到云服务器上呢?可能有人会说,博主你前篇不是讲了java工程的云部署把:但是我想澄清一点的是,我前篇的工程都 ...

  3. 从零开始学android -- 简易的socket通信

    先来介绍下socket,网上摘抄点资料,免得自己打字了 网络中进程之间如何通信? 本地的进程间通信(IPC)有很多种方式,但可以总结为下面4类: 1.消息传递(管道.FIFO.消息队列) 2.同步(互 ...

  4. JSP 与 PHP、ASP、ASP.NET 等语言类似,运行在服务端的语言。

    JSP(全称Java Server Pages)是由 Sun Microsystems 公司倡导和许多公司参与共同创建的一种使软件开发者可以响应客户端请求,而动态生成 HTML.XML 或其他格式文档 ...

  5. ASP.NET动态网站制作(18)-- jq作业讲解及知识补充

    前言:这节课主要讲解js及jq作业,并在作业讲解完后补充关于jQuery的一些知识点. 内容: 1.作业讲解:计算器那一块考虑的各种情况还不算完善,只实现了基本的功能,还需多多练习使用jQuery. ...

  6. onCreate中获得控件的大小

    @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setC ...

  7. PHP-Manual的学习----【语言参考】----【类型】-----【string字符串型】

    1.一个字符串 string 就是由一系列的字符组成,其中每个字符等同于一个字节.这意味着 PHP 只能支持 256 的字符集,因此不支持 Unicode .2. string 最大可以达到 2GB. ...

  8. ACM暑假集训第三周小结

    这一周学的图论,学了这么些 两种存图的方法:邻接矩阵( map[n][n] ) , 邻接表( headlis[n] , vector<int> G[n] )存图的方法,各有各的好,我的理解 ...

  9. IntelliJ IDEA集成JProfiler,入门教程

    说明: JProfiler是用于分析J2EE软件性能瓶颈并能准确定位到Java类或者方法有效解决性能问题的主流工具,它通常需要与性能测试工具如:LoadRunner配合使用,因为往往只有当系统处于压力 ...

  10. intellij idea 自动生成setter getter

    windows下: alt + insert,然后选择要生成的成员. mac下: command + N