题意:求一个序列中本质不同的连续子序列的最大值之和。
由于要求“本质不同”,所以后缀数组就派上用场了,可以从小到大枚举每个后缀,对于每个sa[i],从sa[i]+ht[i]开始枚举(ht[0]=0),这样就能不重复不遗漏地枚举出每一个子串。
但是这样做,最坏情况仍旧是$O(n^2)$的,可能会被卡掉,需要进一步优化。
对于每个sa[i],设k=sa[i]+ht[i],则问题转化成了求max(s[sa[i]],s[sa[i]+1],...,s[k])+max(s[sa[i]],s[sa[i]+1],...,s[k+1])+...+max(s[sa[i]],s[sa[i]+1],...,s[n-1])。
可以发现,随着下标的增大,最大值是单调不减的,这启示我们利用单调栈将后缀进行分段,对于每个最大值不同的段求出后缀和,对于每个sa[i],利用RMQ求出s[sa[i],k]中的最大值mx,然后在单调栈上二分找到第一个大于mx的值的下标,将贡献分成左右两部分相加即可。
一开始可以将初始序列离散化,求出后缀数组后再还原回去,这样复杂度就不依赖于序列元素的大小而只与序列长度有关了,$O(nlogn)$
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int N=2e5+10,inf=0x3f3f3f3f; 5 int s[N],buf1[N],buf2[N],b[N],nb,c[N],n,sa[N],ht[N],rnk[N],ST[N][20],Log[N],sta[N],idx[N],tp; 6 ll sum[N]; 7 void Sort(int* x,int* y,int m) { 8 for(int i=0; i<m; ++i)c[i]=0; 9 for(int i=0; i<n; ++i)++c[x[i]]; 10 for(int i=1; i<m; ++i)c[i]+=c[i-1]; 11 for(int i=n-1; i>=0; --i)sa[--c[x[y[i]]]]=y[i]; 12 } 13 void da(int* s,int n,int m=1000) { 14 int *x=buf1,*y=buf2; 15 x[n]=y[n]=-1; 16 for(int i=0; i<n; ++i)x[i]=s[i],y[i]=i; 17 Sort(x,y,m); 18 for(int k=1; k<n; k<<=1) { 19 int p=0; 20 for(int i=n-k; i<n; ++i)y[p++]=i; 21 for(int i=0; i<n; ++i)if(sa[i]>=k)y[p++]=sa[i]-k; 22 Sort(x,y,m),p=1,y[sa[0]]=0; 23 for(int i=1; i<n; ++i)y[sa[i]]=x[sa[i-1]]==x[sa[i]]&&x[sa[i-1]+k]==x[sa[i]+k]?p-1:p++; 24 if(p==n)break; 25 swap(x,y),m=p; 26 } 27 } 28 void getht() { 29 for(int i=0; i<n; ++i)rnk[sa[i]]=i; 30 ht[0]=0,s[n]=-1; 31 for(int i=0,k=0; i<n; ++i) { 32 if(k)--k; 33 if(!rnk[i])continue; 34 for(; s[i+k]==s[sa[rnk[i]-1]+k]; ++k); 35 ht[rnk[i]]=k; 36 } 37 } 38 void build() { 39 for(int i=0; i<n; ++i)ST[i][0]=s[i]; 40 for(int k=1; k<=Log[n]; ++k) 41 for(int i=0; i+(1<<k)-1<n; ++i) 42 ST[i][k]=max(ST[i][k-1],ST[i+(1<<(k-1))][k-1]); 43 } 44 int qry(int L,int R) { 45 int k=Log[R-L+1]; 46 return max(ST[L][k],ST[R-(1<<k)+1][k]); 47 } 48 struct QR { 49 int k,mx; 50 bool operator<(const QR& b)const {return k<b.k;} 51 } qr[N]; 52 void push(int x,int i) { 53 for(; ~tp&&x>=sta[tp]; --tp); 54 sta[++tp]=x,sum[tp]=(ll)x*(idx[tp-1]-i)+sum[tp-1],idx[tp]=i; 55 } 56 int main() { 57 Log[0]=-1; 58 for(int i=1; i<N; ++i)Log[i]=Log[i>>1]+1; 59 int T; 60 for(scanf("%d",&T); T--;) { 61 scanf("%d",&n); 62 for(int i=0; i<n; ++i)scanf("%d",&s[i]); 63 nb=0; 64 for(int i=0; i<n; ++i)b[nb++]=s[i]; 65 sort(b,b+nb),nb=unique(b,b+nb)-b; 66 for(int i=0; i<n; ++i)s[i]=lower_bound(b,b+nb,s[i])-b; 67 da(s,n,n+10),getht(); 68 for(int i=0; i<n; ++i)s[i]=b[s[i]]; 69 build(); 70 ll ans=0; 71 for(int i=0; i<n; ++i) { 72 int k=sa[i]+ht[i]; 73 qr[i]= {k,qry(sa[i],k)}; 74 } 75 sort(qr,qr+n); 76 sta[tp=0]=inf,sum[tp]=0,idx[tp]=n; 77 for(int i=n-1,j=n-1; i>=0; --i) { 78 int k=qr[i].k,mx=qr[i].mx; 79 for(; j>=k; --j)push(s[j],j); 80 int t=lower_bound(sta,sta+tp+1,mx,greater<int>())-sta-1; 81 ans+=(ll)mx*(idx[t]-k)+sum[t]; 82 } 83 printf("%lld ",ans); 84 } 85 return 0; 86 }