bzoj4199: [Noi2015]品酒大会

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

 

posted @ 2015-08-13 14:54  iamCYY  阅读(707)  评论(0编辑  收藏  举报