您的位置:首页 > 其它

bzoj4199: [Noi2015]品酒大会

2015-08-13 14:54 204 查看
http://www.lydsy.com/JudgeOnline/problem.php?id=4199

  给定一个字符串S,设Si表示S从i开始的的后缀。若Si, Sj存在长度为r的公共前缀,则称i和j是r相似的。每个后缀有一个价值vi,一对后缀Si与Sj的价值是vi*vj。对于每个r=0~n-1,统计有多少对r相似的后缀,以及r相似的后缀的最大价值(n≤300000)。

  我们先后缀排序,并得到height值。我们考虑动态维护集合,保证集合内的答案已经统计过了,在合并的时候更新集合与集合间的答案即可。初始每个后缀自己构成一个大小为1的集合。按height从大到小枚举每个后缀,将rank为i的后缀与rank为i-1的后缀合并,他们更新的r即为当前的height。更新答案并用并查集维护集合即可。

#include<bits/stdc++.h>
using namespace std;
const int maxn=300015;
typedef long long int64;
typedef pair<int,int> PII;
int n,v[maxn];char s[maxn];
struct Tsuffix_array{
int sum[maxn],sa[maxn],rank[maxn],tsa[maxn],trank[maxn];
bool cmp(int i,int j,int l){
if (i+l>n||j+l>n) return 0;
return rank[i]==rank[j]&&rank[i+l]==rank[j+l];
}
void suffix_sort(){
int m=255,p,i,j;
for (i=0;i<=m;++i) sum[i]=0;
for (i=1;i<=n;++i) ++sum[rank[i]=s[i]];
for (i=1;i<=m;++i) sum[i]+=sum[i-1];
for (i=n;i>=1;--i) sa[sum[rank[i]]--]=i;
for (j=1,p=0;p<n;j<<=1,m=p){
for (p=0,i=n-j+1;i<=n;++i) tsa[++p]=i;
for (i=1;i<=n;++i) if (sa[i]>j) tsa[++p]=sa[i]-j;
for (i=0;i<=m;++i) sum[i]=0;
for (i=1;i<=n;++i) ++sum[rank[tsa[i]]];
for (i=1;i<=m;++i) sum[i]+=sum[i-1];
for (i=n;i>=1;--i) sa[sum[rank[tsa[i]]]--]=tsa[i];
for (p=trank[sa[1]]=1,i=2;i<=n;++i) trank[sa[i]]=cmp(sa[i],sa[i-1],j)?p:++p;
memcpy(rank,trank,sizeof(int)*(n+1));
}
}
int height[maxn];
void get_height(){
for (int h=0,i=1;i<=n;++i){
if (rank[i]==1) continue;
for (h?--h:0;s[i+h]==s[sa[rank[i]-1]+h];++h);
height[rank[i]]=h;
}
}
int fa[maxn],siz[maxn],fmx[maxn],fmn[maxn];
int find(int u){return u==fa[u]?u:fa[u]=find(fa[u]);}
void merge(int x,int y){
if (siz[x]<siz[y]) swap(x,y);
fa[y]=x;siz[x]+=siz[y];
fmx[x]=max(fmx[x],fmx[y]);
fmn[x]=min(fmn[x],fmn[y]);
}
PII t[maxn];
int64 ans1[maxn],ans2[maxn];
void get_ans(){
for (int i=2;i<=n;++i) t[i-1]=make_pair(height[i],i);
for (int i=1;i<=n;++i) fmx[rank[i]]=fmn[rank[i]]=v[i];
sort(t+1,t+n,greater<PII>());memset(ans2,200,sizeof(ans2));
for (int i=1;i<=n;++i){fa[i]=i;siz[i]=1;}
for (int i=1;i<=n-1;++i){
int x=find(t[i].second-1),y=find(t[i].second);
ans1[t[i].first]+=1ll*siz[x]*siz[y];
ans2[t[i].first]=max(ans2[t[i].first],1ll*fmx[x]*fmx[y]);
ans2[t[i].first]=max(ans2[t[i].first],1ll*fmn[x]*fmx[y]);
ans2[t[i].first]=max(ans2[t[i].first],1ll*fmx[x]*fmn[y]);
ans2[t[i].first]=max(ans2[t[i].first],1ll*fmn[x]*fmn[y]);
merge(x,y);
}
for (int i=n-1;i>=0;--i){
ans1[i]+=ans1[i+1];
ans2[i]=max(ans2[i],ans2[i+1]);
}
for (int i=0;i<=n-1;++i)
printf("%lld %lld\n",ans1[i],!ans1[i]?0:ans2[i]);
}
}SA;
void init(){
scanf("%d%s",&n,s+1);
for (int i=1;i<=n;++i) scanf("%d",&v[i]);
}
void work(){
SA.suffix_sort();
SA.get_height();
SA.get_ans();
}
int main(){
init();
work();
return 0;
}


my code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: