看到这题我就伤心,当初想到了正解却因为各种sb原因没有写……
好吧,其实我的正解是比较挫的……
大家似乎都用了后缀数组,我用了后缀自动机(后缀树)
其实SAM是很好想得,用SAM建出后缀树后
我们考虑树上每个节点对答案的贡献,0相似就不必说了
考虑到任意两个后缀的LCP即这两个后缀所在节点的LCA的节点所能接受的最长子串mx[i]
又每个节点能接收的子串长度为[mx[fa[i]]+1,mx[i]]
我们很容易想出问题1:设节点i的子树内代表后缀的节点个数为s,那么节点i对区间[mx[fa[i]]+1,mx[i]]贡献是s*(s-1)/2
问题2:很显然找出节点i子树内max{最大*次大,最小*次小}(因为有负数),这要dfs序+线段树维护,然后区间覆盖再来个线段树……
总复杂度是O(nlogn),实际是能过的(但是跑得似乎比SA做法慢……)
1 #include<iostream> 2 #include<cmath> 3 #include<cstring> 4 #include<cstdio> 5 #include<stdlib.h> 6 #define ll long long 7 #define N 300005 8 using namespace std; 9 const ll inf=-1000000001; 10 const ll small=-1000000002000000001ll; 11 int go[2*N][26],fa[2*N],w[2*N],mx[2*N],p[2*N],a[2*N],b[2*N],l[2*N],r[2*N]; 12 struct node{ll b1,b2,s1,s2;} tree[8*N]; 13 struct way{int po,next;} e[2*N]; 14 ll ans[4*N][2]; 15 int n,last,t,len; 16 char s[N]; 17 18 void ins(int x,int y) 19 { 20 e[++len].po=y; 21 e[len].next=p[x]; 22 p[x]=len; 23 } 24 25 void add(int c,int x) 26 { 27 int np,nq,q,p=last; 28 np=++t; mx[np]=mx[p]+1; a[np]=x; w[np]=1; 29 for (;p&&!go[p][c];p=fa[p]) go[p][c]=np; 30 if (!p) fa[np]=1; 31 else { 32 q=go[p][c]; 33 if (mx[q]==mx[p]+1) fa[np]=q; 34 else { 35 nq=++t; a[t]=inf; 36 mx[nq]=mx[p]+1; 37 memcpy(go[nq],go[q],sizeof(go[q])); 38 fa[nq]=fa[q]; fa[np]=fa[q]=nq; 39 for (;go[p][c]==q;p=fa[p]) go[p][c]=nq; 40 } 41 } 42 last=go[last][c]; 43 } 44 45 void dfs(int x) 46 { 47 l[x]=++t; b[t]=x; 48 for (int i=p[x];i;i=e[i].next) 49 { 50 int y=e[i].po; 51 dfs(y); w[x]+=w[y]; 52 } 53 r[x]=t; 54 } 55 56 void update(node &a,node x,node y) 57 { 58 if (x.b1>y.b1) 59 { 60 a.b1=x.b1; 61 a.b2=max(x.b2,y.b1); 62 } 63 else { 64 a.b1=y.b1; 65 a.b2=max(x.b1,y.b2); 66 } 67 if (x.s1>y.s1) 68 { 69 a.s1=y.s1; 70 a.s2=min(x.s1,y.s2); 71 } 72 else { 73 a.s1=x.s1; 74 a.s2=min(x.s2,y.s1); 75 } 76 } 77 void build(int i,int l, int r) 78 { 79 if (l==r) 80 { 81 tree[i].b1=a[b[l]]; 82 tree[i].b2=inf; 83 tree[i].s2=-inf; 84 tree[i].s1=(a[b[l]]==inf)?-inf:a[b[l]]; 85 return; 86 } 87 int m=(l+r)>>1; 88 build(i*2,l,m); 89 build(i*2+1,m+1,r); 90 update(tree[i],tree[i*2],tree[i*2+1]); 91 } 92 93 node get(int i,int l,int r,int x, int y) 94 { 95 if (x<=l&&y>=r) return tree[i]; 96 int m=(l+r)>>1; 97 node s,b,c; 98 b.b1=b.b2=c.b1=c.b2=inf; 99 b.s1=b.s2=c.s1=c.s2=-inf; 100 if (x<=m) b=get(i*2,l,m,x,y); 101 if (y>m) c=get(i*2+1,m+1,r,x,y); 102 update(s,b,c); 103 return s; 104 } 105 106 void work(int i,int l,int r,int x,int y,ll a,ll b) 107 { 108 if (x<=l&&y>=r) {ans[i][0]+=a; ans[i][1]=max(ans[i][1],b);} 109 else { 110 int m=(l+r)>>1; 111 if (ans[i][0]) 112 { 113 ans[i*2][0]+=ans[i][0]; ans[i*2+1][0]+=ans[i][0]; 114 ans[i][0]=0; 115 } 116 if (ans[i][1]>small) 117 { 118 ans[i*2][1]=max(ans[i][1],ans[i*2][1]); ans[i*2+1][1]=max(ans[i][1],ans[i*2+1][1]); 119 ans[i][1]=small; 120 } 121 if (x<=m) work(i*2,l,m,x,y,a,b); 122 if (y>m) work(i*2+1,m+1,r,x,y,a,b); 123 } 124 } 125 126 void getans(int i,int l,int r) 127 { 128 if (l==r) 129 { 130 if (ans[i][0]==0) ans[i][1]=0; 131 printf("%lld %lld ",ans[i][0],ans[i][1]); 132 } 133 else { 134 int m=(l+r)>>1; 135 if (ans[i][1]>small) {ans[i*2][1]=max(ans[i][1],ans[i*2][1]); ans[i*2+1][1]=max(ans[i][1],ans[i*2+1][1]);} 136 if (ans[i][0]) {ans[i*2][0]+=ans[i][0]; ans[i*2+1][0]+=ans[i][0];} 137 getans(i*2,l,m); 138 getans(i*2+1,m+1,r); 139 } 140 } 141 142 int main() 143 { 144 scanf("%d",&n); scanf("%s",s+1); 145 for (int i=1; i<=n; i++) scanf("%d",&b[i]); 146 if (n==1) {puts("0 0");return 0;} 147 t=last=1; a[1]=inf; 148 for (int i=n;i;i--) add(s[i]-'a',b[i]); 149 for (int i=2;i<=t; i++) ins(fa[i],i); 150 t=0; dfs(1); 151 build(1,1,t); 152 for (int i=1; i<=n*4;i++) ans[i][1]=small; 153 for (int i=2; i<=t; i++) 154 { 155 if (w[i]<=1) continue; 156 node c=get(1,1,t,l[i],r[i]); 157 ll x=max(c.b1*c.b2,c.s1*c.s2); 158 work(1,1,n-1,mx[fa[i]]+1,mx[i],(ll)(w[i]-1)*(ll)(w[i])/2,x); 159 } 160 printf("%lld %lld ",(ll)(w[1]-1)*(ll)(w[1])/2,max(tree[1].b1*tree[1].b2,tree[1].s1*tree[1].s2)); 161 getans(1,1,n-1); 162 return 0; 163 } 164