bzoj4199: [Noi2015]品酒大会
题面见http://uoj.ac/problem/131
一道后缀数组题
先求出height,然后从大到小枚举每个height。
然后对于每个height值,两端的集合中任意一对后缀的LCP都是这个height。
我们统计答案之后合并两端的集合,用并查集维护即可。
1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<cstring> 5 #include<algorithm> 6 #define maxn 300005 7 #define inf 1LL<<62 8 using namespace std; 9 typedef long long int64; 10 char ch,s[maxn]; 11 int n,val[maxn]; 12 int64 ans[2][maxn]; 13 int fa[maxn],siz[maxn],list[maxn],max_val[maxn],min_val[maxn]; 14 int SA[maxn],rank[maxn],height[maxn],sum[maxn],t1[maxn],t2[maxn]; 15 bool cmp(int x,int y){ 16 if (height[x]!=height[y]) return height[x]>height[y]; 17 return x<y; 18 } 19 bool ok; 20 void read(int &x){ 21 for (ok=0,ch=getchar();!isdigit(ch);ch=getchar()) if (ch=='-') ok=1; 22 for (x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar()); 23 if (ok) x=-x; 24 } 25 void get_SA(){ 26 int *x=t1,*y=t2,m=255,tot=0; 27 for (int i=1;i<=n;i++) sum[x[i]=s[i]]++; 28 for (int i=1;i<=m;i++) sum[i]+=sum[i-1]; 29 for (int i=n;i>=1;i--) SA[sum[x[i]]--]=i; 30 for (int len=1;tot<n;len<<=1,m=tot){ 31 tot=0; 32 for (int i=n-len+1;i<=n;i++) y[++tot]=i; 33 for (int i=1;i<=n;i++) if (SA[i]>len) y[++tot]=SA[i]-len; 34 for (int i=1;i<=m;i++) sum[i]=0; 35 for (int i=1;i<=n;i++) sum[x[y[i]]]++; 36 for (int i=1;i<=m;i++) sum[i]+=sum[i-1]; 37 for (int i=n;i>=1;i--) SA[sum[x[y[i]]]--]=y[i]; 38 swap(x,y),x[SA[1]]=tot=1; 39 for (int i=2;i<=n;i++){ 40 if (y[SA[i]]!=y[SA[i-1]]||y[SA[i]+len]!=y[SA[i-1]+len]) tot++; 41 x[SA[i]]=tot; 42 } 43 } 44 for (int i=1;i<=n;i++) rank[i]=x[i]; 45 } 46 void get_height(){ 47 for (int i=1,j=0;i<=n;i++){ 48 if (rank[i]==1) continue; 49 while (s[i+j]==s[SA[rank[i]-1]+j]) j++; 50 height[rank[i]]=j; 51 if (j>0) j--; 52 } 53 } 54 int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);} 55 void merge(int x,int y){ 56 siz[y]+=siz[x]; 57 max_val[y]=max(max_val[y],max_val[x]); 58 min_val[y]=min(min_val[y],min_val[x]); 59 fa[x]=y; 60 } 61 int main(){ 62 read(n); 63 scanf("%s",s+1); 64 get_SA(),get_height(); 65 for (int i=1;i<=n;i++) read(val[i]); 66 for (int i=1;i<=n;i++) max_val[i]=val[SA[i]]; 67 for (int i=1;i<=n;i++) min_val[i]=val[SA[i]]; 68 for (int i=1;i<=n;i++) fa[i]=i; 69 for (int i=1;i<=n;i++) siz[i]=1; 70 for (int i=1;i<n;i++) list[i]=i+1; 71 for (int i=1;i<=n;i++) ans[1][i]=-inf; 72 sort(list+1,list+n,cmp); 73 for (int i=1;i<n;i++){ 74 int x=find(list[i]-1),y=find(list[i]); 75 ans[0][height[list[i]]]+=1LL*siz[x]*siz[y]; 76 ans[1][height[list[i]]]=max(ans[1][height[list[i]]],1LL*max_val[x]*max_val[y]); 77 ans[1][height[list[i]]]=max(ans[1][height[list[i]]],1LL*max_val[x]*min_val[y]); 78 ans[1][height[list[i]]]=max(ans[1][height[list[i]]],1LL*min_val[x]*max_val[y]); 79 ans[1][height[list[i]]]=max(ans[1][height[list[i]]],1LL*min_val[x]*min_val[y]); 80 merge(x,y); 81 } 82 for (int i=n-2;i>=0;i--) ans[0][i]+=ans[0][i+1],ans[1][i]=max(ans[1][i],ans[1][i+1]); 83 for (int i=0;i<n;i++) printf("%lld %lld\n",ans[0][i],ans[0][i]?ans[1][i]:0); 84 return 0; 85 }