[后缀数组][并查集]luogu P2178 [NOI2015] 品酒大会
题面
https://www.luogu.com.cn/problem/P2178
分析
对酒名用处理出height,按照height从大到小枚举(排除 1 ),由于 LCP(i,j)=min(LCP(k,k-1))(k>i) ,所以在 height 单调递减的情况下,可以用用并查集合并 i 和 i-1 ,则当前 height[i] 相似的字符串有 size[Father(i)]*size[Father(i-1)] 个
同时记录每个集合的最大最小值,再计算相互相乘的的结果记录到 height[i] 相似的最大美味值中
最后不要忘记 r 相似意味着 0~r-1 相似,所以方案数取后缀和,最大美味值取后缀最大值
代码
#include#include #include #include using namespace std; typedef long long ll; const ll Inf=1e18+1; const int N=3e5+10; int n; int sa[N],rk[N],height[N],x[N],y[N],c[N]; int f[N],sz[N],ord[N]; ll sols[N],mxyum[N],ans[N],a[N],mx[N],mn[N]; char s[N]; int Get_F(int x) {return x==f[x]?x:f[x]=Get_F(f[x]);} void Suffix_Array(int n,char *s,int *sa,int *rk) { int m='z',cnt; for (int i=0;i<=m;i++) c[i]=0; for (int i=1;i<=n;i++) c[x[i]=s[i]]++; for (int i=1;i<=m;i++) c[i]+=c[i-1]; for (int i=n;i;i--) sa[c[x[i]]--]=i; for (int j=1;j<=n;j<<=1) { cnt=0; for (int i=n-j+1;i<=n;i++) y[++cnt]=i; for (int i=1;i<=n;i++) if (sa[i]>j) y[++cnt]=sa[i]-j; for (int i=0;i<=m;i++) c[i]=0; for (int i=1;i<=n;i++) c[x[i]]++; for (int i=1;i<=m;i++) c[i]+=c[i-1]; for (int i=n;i;i--) sa[c[x[y[i]]]--]=y[i],y[i]=0; swap(x,y);x[sa[1]]=cnt=1; for (int i=2;i<=n;i++) x[sa[i]]=(y[sa[i]]==y[sa[i-1]]&&y[min(sa[i]+j,n+1)]==y[min(sa[i-1]+j,n+1)]?cnt:++cnt); m=cnt;if (m==n) break; } for (int i=1;i<=n;i++) rk[sa[i]]=i; } void Get_Height(int n,int *sa,int *rk,int *height) { int z=0; for (int i=1;i<=n;i++) { if (rk[i]==1) {height[rk[i]]=0;continue;} if (z) z--; while (i+z<=n&&sa[rk[i]-1]+z<=n&&s[i+z]==s[sa[rk[i]-1]+z]) z++; height[rk[i]]=z; } } bool CMP(int a,int b) {return height[a]>height[b];} int main() { scanf("%d",&n); scanf("%s",s+1); Suffix_Array(n,s,sa,rk);Get_Height(n,sa,rk,height); for (int i=1;i<=n;i++) scanf("%lld",&a[i]),mx[i]=mn[i]=a[i],sz[f[i]=ord[i]=i]=1,mxyum[i]=ans[i]=-Inf; sort(ord+1,ord+n+1,CMP); for (int i=1,x,y;i<=n;i++) if (ord[i]!=1) { x=Get_F(sa[ord[i]]);y=Get_F(sa[ord[i]-1]);f[y]=x; sols[height[ord[i]]]+=1ll*sz[x]*sz[y];sz[x]+=sz[y]; ans[height[ord[i]]]=max(ans[height[ord[i]]],mxyum[x]=max(max(mxyum[x],mxyum[y]),max(max(mx[x]*mx[y],mx[x]*mn[y]),max(mn[x]*mx[y],mn[x]*mn[y])))); mx[x]=max(mx[x],mx[y]);mn[x]=min(mn[x],mn[y]); } for (int i=n-1;~i;i--) sols[i]+=sols[i+1],ans[i]=max(ans[i],ans[i+1]); for (int i=0;i "%lld %lld\n",sols[i],(sols[i]>0)*ans[i]); }