【NOI2015】品酒大会【后缀数组】【并查集】
作者:互联网
题意:给一个长度为N的字符串和一个长度为N的序列A,对于所有的k∈[0,N−1],求选出两个数i,j满足lcp(suffix(i),suffix(j))=k的方案数和Ai×Aj的最大值
数据范围:暴力跑不过
终于有个后缀自动机做不了的了
看到后缀的前缀,显然是后缀数组
显然求出height数组,倒着排序
显然这是单调的
读到一个长度时,就把i和i−1合并并统计答案
显然可以用并查集
对于方案数,维护一个size ,合并的时候相乘再计入答案
对于Ai×Aj的最大值,维护当前A的最大值和次大值
然而有负数。根据意识流,再维护个最小值和次小值
瞎维护一通,信仰AC
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cctype>
#include <algorithm>
#define MAXN 300005
using namespace std;
typedef long long ll;
const ll INF=1e18;
int sa[MAXN],rk[MAXN],tp[MAXN];
int c[MAXN],n,m='z';
int ht[MAXN];
char s[MAXN];
inline void Rsort()
{
for (int i=1;i<=m;i++) c[i]=0;
for (int i=1;i<=n;i++) ++c[rk[i]];
for (int i=1;i<=m;i++) c[i]+=c[i-1];
for (int i=n;i>=1;i--) sa[c[rk[tp[i]]]--]=tp[i];
}
void SA()
{
for (int i=1;i<=n;i++) rk[i]=s[i],tp[i]=i;
Rsort();
for (int w=1,p=0;p<n;m=p,w<<=1)
{
p=0;
for (int i=n-w+1;i<=n;i++) tp[++p]=i;
for (int i=1;i<=n;i++) if (sa[i]>w) tp[++p]=sa[i]-w;
Rsort();
swap(rk,tp),rk[sa[1]]=p=1;
for (int i=2;i<=n;i++)
if (tp[sa[i]]==tp[sa[i-1]]&&tp[sa[i]+w]==tp[sa[i-1]+w]) rk[sa[i]]=p;
else rk[sa[i]]=++p;
}
int p=0;
for (int i=1;i<=n;i++)
{
if (p) --p;
int j=sa[rk[i]-1];
while (s[i+p]==s[j+p]) ++p;
ht[rk[i]]=p;
}
}
int a[MAXN],p[MAXN];
int fa[MAXN];
int find(const int& x){return fa[x]==x? x:fa[x]=find(fa[x]);}
ll mx[MAXN],sc[MAXN],mn[MAXN],cs[MAXN],siz[MAXN];
inline bool cmp(const int& a,const int& b){return ht[a]>ht[b];}
ll ans[MAXN][2],tmp[2];
int main()
{
scanf("%d",&n);
scanf("%s",s+1);
SA();
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
for (int i=1;i<=n;i++) siz[i]=1,fa[i]=p[i]=i,mx[i]=mn[i]=a[sa[i]],sc[i]=-INF,cs[i]=INF;
sort(p+1,p+n+1,cmp);
int cur=n-1;
tmp[1]=-INF;
for (int i=1;i<=n;i++)
{
int x=find(p[i]),y=find(p[i]-1);
tmp[0]+=siz[x]*siz[y];
siz[x]+=siz[y];
if (mx[y]>mx[x]) sc[x]=max(mx[x],sc[y]),mx[x]=mx[y];
else if (mx[y]>sc[x]) sc[x]=mx[y];
if (mn[y]<mn[x]) cs[x]=min(mn[x],cs[y]),mn[x]=mn[y];
else if (mn[y]<cs[x]) cs[x]=mn[y];
tmp[1]=max(tmp[1],max(mx[x]*sc[x],mn[x]*cs[x]));
fa[y]=x;
ans[ht[p[i]]][0]=tmp[0],ans[ht[p[i]]][1]=tmp[1];
}
for (int i=n-1;i>=0;i--) if (ans[i][0]==0&&ans[i][1]==-INF) ans[i][0]=ans[i+1][0],ans[i][1]=ans[i+1][1];
for (int i=0;i<=n-1;i++) printf("%lld %lld\n",ans[i][0],ans[i][1]==-INF? 0:ans[i][1]);
return 0;
}
标签:suffix,int,查集,tp,NOI2015,品酒,MAXN,ans,include 来源: https://blog.csdn.net/luositing/article/details/98643745