[LOJ6198]谢特
description
给你一个字符串和一个数组\(w_i\),定义\(\mbox{LCP}(i,j)\)为\(i,j\)两个后缀的最长公共前缀。求\(\max_{i,j}\mbox{LCP}(i,j)+(w_i\ \mbox{xor}\ w_j)\)。
\(n \le 10^5\)
sol
首先,\(\mbox{LCP}(i,j)\)是后缀排序上的一段连续区间的\(\mbox{Height}\)最小值。
那么我们可以枚举这个最小值出现的位置,那么跨越这个位置的所有点对的\(\mbox{LCP}\)就确定了。
接下来我们只要考虑最大化\(w_i\ \mbox{xor}\ w_j\)。
显然可以用可持久化\(\mbox{Tire}\)树实现,复杂度是查询次数\(\times \log n\)的。
算法流程大致是这样的:先找到\(\mbox{Height}\)最小的位置\(p\),计算所有跨越\(p\)的点对的答案。枚举分割点两侧\(size\)较小的一侧,在可持久化\(\mbox{Tire}\)树上查询它和另一侧异或的最大值。接着两侧被完全割裂开,可以分别递归下去处理。
考虑这个东西的时间复杂度。可以发现这就是一个倒着做的启发式合并,所以复杂度就是\(O(n\log^2n)\)。
当然也可以按\(\mbox{Height}\)从大到小启发式合并,复杂度是一样的。
code
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int gi(){
int x=0,w=1;char ch=getchar();
while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
if (ch=='-') w=0,ch=getchar();
while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return w?x:-x;
}
const int N = 1e5+5;
struct node{int ch[2],sz;}tr[N*35];
int n,t[N],x[N],y[N],SA[N],Rank[N],Height[N],st[19][N],lg[N],rt[N],tot,w[N],ans;
char s[N];
bool cmp(int i,int j,int k){
return y[i]==y[j]&&y[i+k]==y[j+k];
}
void getSA(){
int m=30;
for (int i=1;i<=n;++i) ++t[x[i]=s[i]-'a'+1];
for (int i=1;i<=m;++i) t[i]+=t[i-1];
for (int i=n;i;--i) SA[t[x[i]]--]=i;
for (int k=1;k<=n;k<<=1){
int p=0;
for (int i=0;i<=m;++i) y[i]=0;
for (int i=n-k+1;i<=n;++i) y[++p]=i;
for (int i=1;i<=n;++i) if (SA[i]>k) y[++p]=SA[i]-k;
for (int i=0;i<=m;++i) t[i]=0;
for (int i=1;i<=n;++i) ++t[x[y[i]]];
for (int i=1;i<=m;++i) t[i]+=t[i-1];
for (int i=n;i;--i) SA[t[x[y[i]]]--]=y[i];
swap(x,y);x[SA[1]]=p=1;
for (int i=2;i<=n;++i) x[SA[i]]=cmp(SA[i],SA[i-1],k)?p:++p;
if (p>=n) break;m=p;
}
for (int i=1;i<=n;++i) Rank[SA[i]]=i;
for (int i=1,j=0;i<=n;++i){
if (j) --j;
while (s[i+j]==s[SA[Rank[i]-1]+j]) ++j;
Height[Rank[i]]=j;st[0][i]=i;
}
for (int i=2;i<=n;++i) lg[i]=lg[i>>1]+1;
for (int j=1;j<=lg[n];++j)
for (int i=1;i+(1<<j)-1<=n;++i)
if (Height[st[j-1][i]]<Height[st[j-1][i+(1<<j-1)]])
st[j][i]=st[j-1][i];
else st[j][i]=st[j-1][i+(1<<j-1)];
}
int cal(int l,int r){
int k=lg[r-l+1];
if (Height[st[k][l]]<Height[st[k][r-(1<<k)+1]]) return st[k][l];
return st[k][r-(1<<k)+1];
}
void modify(int &x,int p,int dep){
tr[++tot]=tr[x];++tr[x=tot].sz;
if (!~dep) return;
modify(tr[x].ch[(p>>dep)&1],p,dep-1);
}
int query(int x,int y,int p,int dep){
if (!~dep) return 0;
int c=(p>>dep)&1;c^=1;
if (tr[tr[x].ch[c]].sz-tr[tr[y].ch[c]].sz) return query(tr[x].ch[c],tr[y].ch[c],p,dep-1)|(1<<dep);
c^=1;return query(tr[x].ch[c],tr[y].ch[c],p,dep-1);
}
void solve(int l,int r){
if (l==r) return;int mid=cal(l+1,r)-1;
if (mid-l+1<=r-mid){
for (int i=l;i<=mid;++i)
ans=max(ans,Height[mid+1]+query(rt[r],rt[mid],w[SA[i]],18));
}else{
for (int i=mid+1;i<=r;++i)
ans=max(ans,Height[mid+1]+query(rt[mid],rt[l-1],w[SA[i]],18));
}
solve(l,mid);solve(mid+1,r);
}
int main(){
n=gi();scanf("%s",s+1);getSA();
for (int i=1;i<=n;++i) w[i]=gi();
for (int i=1;i<=n;++i) modify(rt[i]=rt[i-1],w[SA[i]],18);
solve(1,n);printf("%d\n",ans);return 0;
}
[LOJ6198]谢特的更多相关文章
- loj6198谢特 后缀数组+并查集+Trie
先把问题放在后缀数组上考虑 已知两个数组a b,求min(a[i],...,a[j])+(b[i]^b[j])的最大值 套路题 初始每个点都是一个小连通块 把a按从大到小的顺序加入,计算当前加入边作为 ...
- 【loj6198】谢特
Portal -->loj6198 Solution (为什么感觉loj上面这几道后缀数组的题..套路都是一样的啊qwq) 同样也是..考虑某个区间\(height[i]\)的最小值的贡 ...
- 谢欣伦 - OpenDev原创教程 - 媒体开发库libMedia
libMedia是一个免费的简单的媒体开发库,其中的接口类与函数大都以小写的x打头,来源于我的姓氏首字母(谢欣伦). 下载 OpenDev for VS2012 libMedia提供四大功能,一是视频 ...
- 谢欣伦 - OpenDev原创教程 - 蓝牙设备查找类CxBthRadio & CxBthRadioFind
这是一个精练的蓝牙设备查找类,类名.函数名和变量名均采用匈牙利命名法.小写的x代表我的姓氏首字母(谢欣伦),个人习惯而已,如有雷同,纯属巧合. CxBthRadioFind的使用如下: void CU ...
- 谢欣伦 - OpenDev原创教程 - 服务端套接字类CxServerSocket
这是一个精练的服务端套接字类,类名.函数名和变量名均采用匈牙利命名法.小写的x代表我的姓氏首字母(谢欣伦),个人习惯而已,如有雷同,纯属巧合. CxServerSocket的使用如下(以某个叫做CSo ...
- 谢欣伦 - OpenDev原创教程 - 蓝牙设备查找类CxBthRemoteDeviceFind
这是一个精练的蓝牙设备查找类,类名.函数名和变量名均采用匈牙利命名法.小写的x代表我的姓氏首字母(谢欣伦),个人习惯而已,如有雷同,纯属巧合. CxBthRemoteDeviceFind的使用如下: ...
- 谢欣伦 - OpenDev原创教程 - 无连接套接字类CxUdpSocket
这是一个精练的无连接套接字类,类名.函数名和变量名均采用匈牙利命名法.小写的x代表我的姓氏首字母(谢欣伦),个人习惯而已,如有雷同,纯属巧合. CxUdpSocket的使用如下(以某个叫做CSomeC ...
- 谢欣伦 - OpenDev原创教程 - 串口类CxSerial
这是一个精练的串口类,类名.函数名和变量名均采用匈牙利命名法.小写的x代表我的姓氏首字母(谢欣伦),个人习惯而已,如有雷同,纯属巧合. 串口类CxSerial的使用如下(以某个叫做CSomeClass ...
- 谢欣伦 - OpenDev原创教程 - 客户端套接字类CxClientSocket
这是一个精练的客户端套接字类,类名.函数名和变量名均采用匈牙利命名法.小写的x代表我的姓氏首字母(谢欣伦),个人习惯而已,如有雷同,纯属巧合. CxClientSocket的使用如下(以某个叫做CSo ...
随机推荐
- Codeforces Round #513 by Barcelona Bootcamp
A. Phone Numbers 签. #include <bits/stdc++.h> using namespace std; #define N 110 char s[N]; ], ...
- 学号20155311 2016-2017-2 《Java程序设计》第5周学习总结
学号20155311 2016-2017-2 <Java程序设计>第5周学习总结 教材学习内容总结 由于我的ios系统出了一些问题,所以git idea jdk我都重新在windows系统 ...
- python按行读取文件,如何去掉换行符"\n"
for line in file.readlines(): line=line.strip('\n')
- linux 异常
1. NoRouteToHostException异常问题的原因及解决 (转自:http://performtest163.blog.163.com/blog/static/1400769642011 ...
- Java中com.jcraft.jsch.ChannelSftp讲解
http://blog.csdn.net/allen_zhao_2012/article/details/7941631 http://www.cnblogs.com/longyg/archive/2 ...
- 前端学习笔记之HTTP协议
阅读目录 一 HTTP协议简介 二 HTTP协议之请求Request 三 HTTP协议之响应Response 四 HTTP协议完整工作流程 五 HTTP协议关键性总结 六 自定义套接字分析HTTP协议 ...
- Bootstrap and Angular
- Java FastJson 介绍
1.前言 1.1.FastJson的介绍: JSON协议使用方便,越来越流行,JSON的处理器有很多,这里我介绍一下FastJson,FastJson是阿里的开源框架,被不少企业使用,是一个极其优秀的 ...
- UVa 11021 麻球繁衍
https://vjudge.net/problem/UVA-11021 题意:有k只麻球,每只活一天就会死亡,临死之前可能会生出一些新的麻球.具体来说,生i个麻球的概率为Pi.给定m,求m天后所有麻 ...
- javascript debugger
打开调试工具,刷新,可以看到脚本被暂停 <!DOCTYPE html> <html> <head> <meta charset="utf-8&quo ...