[NOI2015][BZOJ4199] 品酒大会|后缀数组|并查集
八中并没有题面……
后缀数组
即lcp(i,j)=l的后缀对的数量及w[i]*w[j]的最大值。
按height从大到小处理,把相邻的合并到一起,并查集维护。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<algorithm> 6 #include<cmath> 7 #define inf 1ll<<62 8 #define ll long long 9 #define N 300005 10 using namespace std; 11 char s[N]; 12 int len,w[N]; 13 int fa[N],size[N],list[N],max_val[N],min_val[N]; 14 int sa[N],rank[N],height[N],t1[N],t2[N],cc[N]; 15 ll ans[2][N]; 16 inline int read() 17 { 18 int a=0,f=1; char c=getchar(); 19 while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();} 20 while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();} 21 return a*f; 22 } 23 inline bool cmp(int x,int y) 24 { 25 return height[x]==height[y]?x>y:height[x]>height[y]; 26 } 27 inline bool cmp0(int *y,int a,int b,int k) 28 { 29 int arank1=y[a]; 30 int brank1=y[b]; 31 int arank2=a+k>=len?-1:y[a+k]; 32 int brank2=b+k>=len?-1:y[b+k]; 33 return arank1==brank1&&arank2==brank2; 34 } 35 inline void make_sa() 36 { 37 int m=256; 38 int *x=t1,*y=t2; 39 for (int i=0;i<m;i++) cc[i]=0; 40 for (int i=0;i<len;i++) ++cc[x[i]=s[i]]; 41 for (int i=1;i<m;i++) cc[i]+=cc[i-1]; 42 for (int i=len-1;i>=0;i--) sa[--cc[x[i]]]=i; 43 for (int k=1;k<len;k<<=1) 44 { 45 int p=0; 46 for (int i=len-k;i<len;i++) y[p++]=i; 47 for (int i=0;i<len;i++) 48 if (sa[i]>=k) y[p++]=sa[i]-k; 49 for (int i=0;i<m;i++) cc[i]=0; 50 for (int i=0;i<len;i++) ++cc[x[y[i]]]; 51 for (int i=1;i<m;i++) cc[i]+=cc[i-1]; 52 for (int i=len-1;i>=0;i--) sa[--cc[x[y[i]]]]=y[i]; 53 swap(x,y); 54 m=1; x[sa[0]]=0; 55 for (int i=1;i<len;i++) 56 x[sa[i]]=cmp0(y,sa[i-1],sa[i],k)?m-1:m++; 57 if (m>=len) break; 58 } 59 } 60 inline void make_height() 61 { 62 for (int i=0;i<len;i++) rank[sa[i]]=i; 63 int k=0; height[0]=0; 64 for (int i=0;i<len;i++) 65 { 66 if (!rank[i]) continue; 67 int j=sa[rank[i]-1]; 68 if (k) k--; 69 while (s[i+k]==s[j+k]) k++; 70 height[rank[i]]=k; 71 } 72 } 73 int find(int x) {return fa[x]==x?x:fa[x]=find(fa[x]);} 74 75 inline void merge(int x,int y) 76 { 77 size[y]+=size[x]; 78 max_val[y]=max(max_val[y],max_val[x]); 79 min_val[y]=min(min_val[y],min_val[x]); 80 fa[x]=y; 81 } 82 int main() 83 { 84 len=read(); 85 scanf("%s",s); 86 for (int i=0;i<len;i++) w[i]=read(); 87 make_sa(); 88 make_height(); 89 for (int i=0;i<len;i++) 90 { 91 max_val[i]=min_val[i]=w[sa[i]]; 92 fa[i]=i; 93 size[i]=1; 94 list[i]=i; 95 ans[1][i]=-inf; 96 } 97 sort(list,list+len,cmp); 98 99 for (int i=0;i<len-1;i++) 100 { 101 int x=find(list[i]-1),y=find(list[i]); 102 ans[0][height[list[i]]]+=1ll*size[x]*size[y]; 103 ans[1][height[list[i]]]=max(ans[1][height[list[i]]],1ll*max_val[x]*max_val[y]); 104 ans[1][height[list[i]]]=max(ans[1][height[list[i]]],1ll*max_val[x]*min_val[y]); 105 ans[1][height[list[i]]]=max(ans[1][height[list[i]]],1ll*min_val[x]*max_val[y]); 106 ans[1][height[list[i]]]=max(ans[1][height[list[i]]],1ll*min_val[x]*min_val[y]); 107 merge(x,y); 108 } 109 for (int i=len-2;i>=0;i--) ans[0][i]+=ans[0][i+1],ans[1][i]=max(ans[1][i],ans[1][i+1]); 110 for (int i=0;i<len;i++) printf("%lld %lld\n",ans[0][i],ans[0][i]?ans[1][i]:0); 111 return 0; 112 }