[bzoj4199][Noi2015]品酒大會——後綴數組
阿新 • • 發佈:2019-02-06
過程 work push 連通塊 void tor find isdigit 最大值
題目大意:
給定一個序列,定義兩個後綴是k相似的當且僅當這兩個後綴有長度為k的公共前綴。
求對任意\(r\in [0,n-1]\),\(r\)相似的後綴的對數和兩個後綴乘積的最大值。
思路:
先考慮後綴數組是如何計算兩個後綴的lcp,發現是對於一段連續的height取min。
於是對於制定的相似度r,height < r的位置必定是兩個後綴不能越過的,於是不難發現將有height \(\ge\)r的位置給取出來,然後整個序列分成了若幹個連通塊,一對具有r相似的後綴必定同時在一個聯通快裏面。
對於一個連通塊,我們要得到答案所需要的信息即為最大值,次大值,最小值,次小值和長度。
於是直接從大到小計算答案,每次將若幹個塊連接,中間的過程用並查集維護。
/*======================================= * Author : ylsoi * Time : 2019.2.6 * Problem : luogu2178 * E-mail : [email protected] * ====================================*/ #include<bits/stdc++.h> #define REP(i,a,b) for(int i=a,i##_end_=b;i<=i##_end_;++i) #define DREP(i,a,b) for(int i=a,i##_end_=b;i>=i##_end_;--i) #define debug(x) cout<<#x<<"="<<x<<" " #define fi first #define se second #define mk make_pair #define pb push_back typedef long long ll; using namespace std; void File(){ freopen("luogu2178.in","r",stdin); freopen("luogu2178.out","w",stdout); } template<typename T>void read(T &_){ _=0; T fl=1; char ch=getchar(); for(;!isdigit(ch);ch=getchar())if(ch=='-')fl=-1; for(;isdigit(ch);ch=getchar())_=(_<<1)+(_<<3)+(ch^'0'); _*=fl; } const int maxn=3e5+10; const int inf=0x3f3f3f3f; const ll INF=2e18; int n; char s[maxn]; ll a[maxn]; int sz,sa[maxn],rk[maxn],tp[maxn],tax[maxn],height[maxn]; void radix_sort(){ REP(i,1,sz)tax[i]=0; REP(i,1,n)++tax[rk[i]]; REP(i,1,sz)tax[i]+=tax[i-1]; DREP(i,n,1)sa[tax[rk[tp[i]]]--]=tp[i]; } void suffix_sort(){ sz=26; REP(i,1,n)rk[i]=s[i]-'a'+1,tp[i]=i; radix_sort(); for(int w=1,p=0;w<n;w<<=1){ p=0; REP(i,1,w)tp[++p]=n-w+i; REP(i,1,n)if(sa[i]>w)tp[++p]=sa[i]-w; radix_sort(); swap(rk,tp); rk[sa[1]]=p=1; REP(i,2,n) if(tp[sa[i-1]]==tp[sa[i]] && tp[sa[i-1]+w]==tp[sa[i]+w])rk[sa[i]]=p; else rk[sa[i]]=++p; sz=p; if(sz==n)break; } //REP(i,1,n)cout<<s+sa[i]<<endl; int p=0; REP(i,1,n){ if(p)--p; int j=sa[rk[i]-1]; while(s[i+p]==s[j+p])++p; height[rk[i]]=p; } } struct node{ ll l,r,mx[2],mn[2]; }c[maxn]; node operator + (node x,node y){ node ret; ret.l=min(x.l,y.l); ret.r=max(x.r,y.r); if(x.mx[0]<y.mx[0])swap(x,y); ret.mx[0]=x.mx[0]; ret.mx[1]=max(x.mx[1],y.mx[0]); if(x.mn[0]>y.mn[0])swap(x,y); ret.mn[0]=x.mn[0]; ret.mn[1]=min(x.mn[1],y.mn[0]); return ret; } int fa[maxn]; int find(int x){return fa[x]==x ? x : fa[x]=find(fa[x]);} ll sum,mx=-INF; node t; void merge(int x,int y){ x=find(x),y=find(y); //debug(x),debug(y)<<endl; if(x==y)return; sum-=(c[x].r-c[x].l+1)*(c[x].r-c[x].l+2)/2; sum-=(c[y].r-c[y].l+1)*(c[y].r-c[y].l+2)/2; c[x]=c[x]+c[y]; sum+=(c[x].r-c[x].l+1)*(c[x].r-c[x].l+2)/2; t=c[c[x].l-1]+c[x]; mx=max(mx,t.mx[0]*t.mx[1]); mx=max(mx,t.mn[0]*t.mn[1]); fa[y]=x; } vector<int>lis[maxn]; pair<ll,ll>ans[maxn]; void work(){ REP(i,1,n){ fa[i]=i; c[i]=(node){i,i,{a[sa[i]],-inf},{a[sa[i]],inf}}; if(i>1)lis[height[i]].pb(i); } DREP(i,n-1,0){ REP(j,0,lis[i].size()-1){ ++sum; mx=max(mx,c[lis[i][j]].mx[0]*c[lis[i][j]-1].mx[0]); } //debug(i)<<endl; REP(j,0,lis[i].size()-1){ //debug(lis[i][j]); if(lis[i][j]>2 && height[lis[i][j]-1]>=i)merge(lis[i][j],lis[i][j]-1); if(lis[i][j]<n && height[lis[i][j]+1]>=i)merge(lis[i][j],lis[i][j]+1); } //cout<<endl; ans[i]=mk(sum,mx); } REP(i,0,n-1)printf("%lld %lld\n",ans[i].fi,ans[i].se==-INF ? 0 : ans[i].se); } int main(){ File(); read(n); scanf("%s",s+1); REP(i,1,n)read(a[i]); suffix_sort(); work(); return 0; }
[bzoj4199][Noi2015]品酒大會——後綴數組