题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=4199
题意:
给你一个长度为n的字符串s,和一个长为n的数组v。
对于每个整数r∈[0,n-1]:
(1)问你有多少对后缀(suffix(i), suffix(j)),满足LCP(suffix(i), suffix(j)) >= r
(2)输出mul[r] = max(v[i]*v[j]),其中i,j满足(1)的条件
题解:
先考虑第(1)问。
由于LCP只受连续的一段height中最小值的影响
所以先将height数组排序,然后按height从大到小的顺序,合并当前height对应的两个后缀suffix(i)和suffix(j)所在的集合。
那么对于任意两个分别属于这两个集合的后缀来说,它们的LCP一定为当前height。
假设ans[r]表示LCP恰好为r的后缀对个数,那么此时的贡献为ans[height] += siz[find(i)] * siz[find(j)]
最后对ans数组求一遍后缀和,即为LCP >= r的后缀对个数。
然后再考虑第(2)问。
由于v[i]有可能为负值,所以对于每个集合,维护集合中元素对应v[i]的最大值和最小值。
那么每次合并时,用max(两个集合的最大值之积,最小值之积)更新mul[par]即可。
AC Code:
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 #include <algorithm> 5 #define MAX_N 300005 6 7 using namespace std; 8 9 struct Height 10 { 11 int v,id; 12 Height(int _v,int _id) 13 { 14 v=_v; id=_id; 15 } 16 Height(){} 17 friend bool operator < (const Height &a,const Height &b) 18 { 19 return a.v<b.v; 20 } 21 }; 22 23 int n; 24 int a[MAX_N]; 25 int sa[MAX_N]; 26 int rk[MAX_N]; 27 int t1[MAX_N]; 28 int t2[MAX_N]; 29 int cnt[MAX_N]; 30 int tsa[MAX_N]; 31 int height[MAX_N]; 32 int par[MAX_N]; 33 long long siz[MAX_N]; 34 long long maxn[MAX_N]; 35 long long minn[MAX_N]; 36 long long v[MAX_N]; 37 long long ans[MAX_N]; 38 long long mul[MAX_N]; 39 char s[MAX_N]; 40 Height h[MAX_N]; 41 42 void rsort() 43 { 44 memset(cnt,0,sizeof(cnt)); 45 for(int i=1;i<=n;i++) cnt[t2[i]]++; 46 for(int i=1;i<=n;i++) cnt[i]+=cnt[i-1]; 47 for(int i=n;i>=1;i--) tsa[cnt[t2[i]]--]=i; 48 memset(cnt,0,sizeof(cnt)); 49 for(int i=1;i<=n;i++) cnt[t1[i]]++; 50 for(int i=1;i<=n;i++) cnt[i]+=cnt[i-1]; 51 for(int i=n;i>=1;i--) sa[cnt[t1[tsa[i]]]--]=tsa[i]; 52 } 53 54 void suffix() 55 { 56 memset(cnt,0,sizeof(cnt)); 57 for(int i=1;i<=n;i++) a[i]=s[i],cnt[a[i]]++; 58 for(int i=‘a‘;i<=‘z‘;i++) cnt[i]+=cnt[i-1]; 59 for(int i=1;i<=n;i++) rk[i]=cnt[a[i]]; 60 int len=1; 61 while(len<n) 62 { 63 for(int i=1;i<=n;i++) 64 { 65 t1[i]=rk[i]; 66 t2[i]=i+len<=n ? rk[i+len] : 0; 67 } 68 rsort(); 69 for(int i=1;i<=n;i++) 70 { 71 rk[sa[i]]=rk[sa[i-1]]+(t1[sa[i]]!=t1[sa[i-1]] || t2[sa[i]]!=t2[sa[i-1]]); 72 } 73 len<<=1; 74 } 75 int k=0; 76 for(int i=1;i<=n;i++) 77 { 78 k=k?k-1:k; 79 int j=sa[rk[i]-1]; 80 while(a[i+k]==a[j+k]) k++; 81 height[rk[i]]=k; 82 } 83 } 84 85 void init_union_find() 86 { 87 for(int i=1;i<=n;i++) 88 { 89 par[i]=i; 90 siz[i]=1; 91 maxn[i]=minn[i]=v[i]; 92 } 93 } 94 95 int find(int x) 96 { 97 return par[x]==x ? x : par[x]=find(par[x]); 98 } 99 100 void unite(int x,int y,int r) 101 { 102 int px=find(x); 103 int py=find(y); 104 ans[r]+=siz[px]*siz[py]; 105 mul[r]=max(mul[r],max(maxn[px]*maxn[py],minn[px]*minn[py])); 106 siz[py]+=siz[px]; 107 maxn[py]=max(maxn[py],maxn[px]); 108 minn[py]=min(minn[py],minn[px]); 109 par[px]=py; 110 } 111 112 void read() 113 { 114 scanf("%d%s",&n,s+1); 115 for(int i=1;i<=n;i++) scanf("%lld",&v[i]); 116 } 117 118 void work() 119 { 120 suffix(); 121 init_union_find(); 122 for(int i=2;i<=n;i++) h[i]=Height(height[i],i); 123 sort(h+2,h+1+n); 124 memset(ans,0,sizeof(ans)); 125 memset(mul,0x80,sizeof(mul)); 126 for(int i=n;i>=2;i--) unite(sa[h[i].id],sa[h[i].id-1],h[i].v); 127 for(int i=n-1;i>=0;i--) ans[i]+=ans[i+1],mul[i]=max(mul[i],mul[i+1]); 128 for(int i=0;i<n;i++) 129 { 130 if(ans[i]) printf("%lld %lld\n",ans[i],mul[i]); 131 else printf("0 0\n"); 132 } 133 } 134 135 int main() 136 { 137 read(); 138 work(); 139 }