luoguP2178 [NOI2015]品酒大会(后缀数组做法)
题意
因为一个\(k\)相似必定为\(k-1,k-2....0\)相似,对于一个\(lcp\)为\(k\)后缀对\((i,j)\),我们只用把它的贡献加在\(k\)的答案上,最后求一个后缀和和后缀max就可以得到答案。
考虑如何快速计算后缀对的贡献:
因为后缀对\((i,j),i>j\)的\(lcp\)是\(min_{k=i+1}^{j}height_k\),因此考虑将\(height\)从大到小排序。
对于当前的\(height_i\),我们找到\(sa_{i-1}\)和\(sa_i\)所在后缀集合(一开始每个后缀是单独一个集合)。这时两个集合分别选两个后缀配对,\(lcp\)必定为\(height_i\),于是\(ans[height_i]\)就加上两集合大小的乘积,之后合并两个集合。第一问就做完了。
第二问只需要对每个集合维护最大值和最小值(负数乘负数会变成正数),合并时取个max即可。
code:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=3*1e5+10;
int n,num;
int fa[maxn],size[maxn];
ll a[maxn],maxx[maxn],minn[maxn],ans1[maxn],ans2[maxn];
char s[maxn];
struct node{int height,id;}h[maxn];
struct SA
{
int num;
int sa[maxn],rk[maxn],oldrk[maxn],id[maxn],tmpid[maxn],cnt[maxn],height[maxn];
inline bool check(int x,int y,int k){return oldrk[x]==oldrk[y]&&oldrk[x+k]==oldrk[y+k];}
inline void build(char* s,int len)
{
int num=300;
for(int i=1;i<=len;i++)cnt[rk[i]=s[i]]++;
for(int i=1;i<=num;i++)cnt[i]+=cnt[i-1];
for(int i=len;i;i--)sa[cnt[rk[i]]--]=i;
for(int t=1;t<=len;t<<=1)
{
int tot=0;
for(int i=len-t+1;i<=len;i++)id[++tot]=i;
for(int i=1;i<=len;i++)if(sa[i]>t)id[++tot]=sa[i]-t;
tot=0;
memset(cnt,0,sizeof(cnt));
for(int i=1;i<=len;i++)cnt[tmpid[i]=rk[id[i]]]++;
for(int i=1;i<=num;i++)cnt[i]+=cnt[i-1];
for(int i=len;i;i--)sa[cnt[tmpid[i]]--]=id[i];
memcpy(oldrk,rk,sizeof(rk));
for(int i=1;i<=len;i++)rk[sa[i]]=check(sa[i-1],sa[i],t)?tot:++tot;
num=tot;
if(num==len)break;
}
for(int i=1,j=0;i<=len;i++)
{
if(j)j--;
while(s[i+j]==s[sa[rk[i]-1]+j])j++;
height[rk[i]]=j;
}
}
}Sa;
inline ll read()
{
char c=getchar();ll res=0,f=1;
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9')res=res*10+c-'0',c=getchar();
return res*f;
}
inline bool cmp(node x,node y){return x.height>y.height;}
int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
inline void merge(int x,int y,int k)
{
int p=find(x),q=find(y);
if(size[p]>size[q])swap(p,q);
ans1[k]+=1ll*size[p]*size[q];
ans2[k]=max(ans2[k],max(maxx[p]*maxx[q],minn[p]*minn[q]));
minn[q]=min(minn[q],minn[p]);
maxx[q]=max(maxx[q],maxx[p]);
fa[p]=q;size[q]+=size[p];
}
int main()
{
n=read();
scanf("%s",s+1);
Sa.build(s,n);
for(int i=1;i<=n;i++)a[i]=read();
for(int i=1;i<=n;i++)fa[i]=i,size[i]=1,maxx[i]=minn[i]=a[i];
for(int i=2;i<=n;i++)h[i]=(node){Sa.height[i],i};
sort(h+2,h+n+1,cmp);
memset(ans2,-0x3f,sizeof(ans2));
for(int i=2;i<=n;i++)merge(Sa.sa[h[i].id-1],Sa.sa[h[i].id],h[i].height);
for(int i=n-1;~i;i--)ans1[i]+=ans1[i+1],ans2[i]=max(ans2[i],ans2[i+1]);
for(int i=0;i<n;i++)
if(ans1[i])printf("%lld %lld\n",ans1[i],ans2[i]);
else puts("0 0");
return 0;
}
luoguP2178 [NOI2015]品酒大会(后缀数组做法)的更多相关文章
- BZOJ 4199: [Noi2015]品酒大会 [后缀数组 带权并查集]
4199: [Noi2015]品酒大会 UOJ:http://uoj.ac/problem/131 一年一度的“幻影阁夏日品酒大会”隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发“首席品 ...
- [UOJ#131][BZOJ4199][NOI2015]品酒大会 后缀数组 + 并查集
[UOJ#131][BZOJ4199][NOI2015]品酒大会 试题描述 一年一度的“幻影阁夏日品酒大会”隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发“首席品酒家”和“首席猎手”两个 ...
- 【BZOJ4199】[Noi2015]品酒大会 后缀数组+并查集
[BZOJ4199][Noi2015]品酒大会 题面:http://www.lydsy.com/JudgeOnline/wttl/thread.php?tid=2144 题解:听说能用SAM?SA默默 ...
- [NOI2015] 品酒大会 - 后缀数组,并查集,STL,启发式合并
[NOI2015] 品酒大会 Description 对于每一个 \(i \in [0,n)\) 求有多少对后缀满足 LCP 长度 \(\le i\) ,并求满足条件的两个后缀权值乘积的最大值. So ...
- BZOJ.4199.[NOI2015]品酒大会(后缀数组 单调栈)
BZOJ 洛谷 后缀自动机做法. 洛谷上SAM比SA慢...BZOJ SAM却能快近一倍... 显然只需要考虑极长的相同子串的贡献,然后求后缀和/后缀\(\max\)就可以了. 对于相同子串,我们能想 ...
- NOI2015品酒大会 后缀数组
自己尝试敲后缀数组,发现难看(tiao)的不行,于是抄了板子 考虑建出hei以后转化出的问题: 对于一个数组中权值大于等于k的连续部分,求取两个数的方案数和两数积的最大值 (好气啊,可以有负数) 把询 ...
- BZOJ 4199: [Noi2015]品酒大会( 后缀数组 + 并查集 )
求出后缀数组后, 对height排序, 从大到小来处理(r相似必定是0~r-1相似), 并查集维护. 复杂度O(NlogN + Nalpha(N)) ------------------------- ...
- luoguP2178 [NOI2015]品酒大会(后缀自动机)
题意 承接上篇题解 考虑两个后缀的\(lcp\)是什么,是将串反着插入后缀自动机后两个前缀(终止节点)的\(lca\)!!!于是可以在parent tree上DP了. 比后缀数组又简单又好写跑的还快. ...
- 【学术篇】NOI2015 品酒大会 后缀数组+并查集
省选前大致是刷不了几道题了... 所以就找一些裸一点的题目练练板子算了= = 然而这题一点都不裸, 也并不怎么好写... 于是就浪费了将近一下午的时间... 然而还不是因为后缀数组板子不熟= = 首先 ...
随机推荐
- IDEA如何打包可运行jar,外部引用jar包版
背景: 有时候,我们会用IDEA来开发一些小工具,需要打成可运行的JAR包:或者某些项目不是WEB应用,纯粹是后台应用,发布时,也需要打成可运行的JAR包.并且,如果依赖第三方jar时,又不希望第三方 ...
- 4.P1产品经理该如何学习提升
0经验.想转型 对于想转型或者没有经验的人,这部分同学你肯定对产品本身有一定的了解了,但是在这个时候转型最痛苦的是你要从原来的工作转到一个新的工作中的时候,要回到一个原点.比如你是原来是做开发的,那么 ...
- 2019csp-s
11.17一切尘埃落定 回来之后一直“沉迷”文化课,不想去面对自己,更多的可能是不敢吧 晃晃悠悠一个星期过去了 其实信息学考完就知道成绩了,很垃圾,不想去想,所以沉迷解析几何无法自拔(但好像也做不对几 ...
- Linux下修改Mysql密码的三种方式
前言 有时我们会忘记Mysql的密码,或者想改一个密码,以下将对这两种情况修改密码的三种解决方法做个总结 本文都以用户为 root 为例 一.拥有原来的myql的root的密码 方法一: 在mysql ...
- 使用Runtime的hook技术为tableView实现一个空白缺省页
一.介绍 UITableView和UICollectionView是iOS开发最常用的控件,也是必不可少的控件,这两个控件基本能实现各种各样的界面样式. 它们都是通过代理模式监测数据源的有无对数据进行 ...
- php+laravel依赖注入浅析
laravel容器包含控制反转和依赖注入,使用起来就是,先把对象bind好,需要时可以直接使用make来取就好. 通常我们的调用如下. $config = $container->make('c ...
- ImportError: unable to find Qt5Core.dll on PATH
一.实验环境 1.Windows7x32_SP1 2.python3.7.4 3.pyinstaller3.5 二.问题描述 1.一直都是在Windows10x64上使用pyinstaller打包ex ...
- linux如何修改权限详解
前言 今日,同事问我,服务器上拷贝过来的tomcat,怎么执行不了./startup.sh.于是,我一想,那肯定是没有权限的问题了.于是使用chmod命令更改了权限后,就可以执行了.项目正常启动.我想 ...
- SpringMVC详解------参数绑定
SpringMVC详解------参数绑定 转载于:https://blog.csdn.net/swebin/article/details/92795422 目录 1.SpringMVC 参数绑定 ...
- CountDownLatch(闭锁)、Semaphore(信号量)、CyclicBarrier
一.CountDowmLatch(闭锁)(倒计数锁存器) CountDownLatch类位于java.util.concurrent包下,在完成某些运算时,只有其他所有线程的运算全部完成,当前运算才继 ...