Gym

题意:求一个序列中本质不同的连续子序列的最大值之和。

由于要求“本质不同”,所以后缀数组就派上用场了,可以从小到大枚举每个后缀,对于每个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 }
原文地址:https://www.cnblogs.com/asdfsag/p/11681118.html