题意:
求已知序列的所有本质不同的子区间的最大值之和。
题解:
对于每一个位置i,我们需要计算出最短的区间[i,j],使得[i,j]的字符串没有被算过,那么[i,j+1],[i,j+2],[i,j+3]...[i,n]都不会被算过。
统计答案很容易,方法应该也不少。我的做法是定义每一个点的父亲为后面第一个比它大的位置,然后倍增一下再计算一下就可以算出答案。
接下来就是如何求出上述区间,其实就是需要求出一个最小的值a,满足所有后缀j(j<i)与后缀i的最长公共前缀小于a。
然后我考场上以为两个log是可以过的,就直接写了个二分,然后SA上再来了个二分,于是愉快的TLE了。
后来想卡常,但是怎么都卡不过去只好又写了一大堆代码改成了一个log的做法,具体如下
其实我们只需要知道前i-1个后缀中在SA上位置最接近第i个后缀在SA上的位置的那左右两个即可,然后用rmq求一下height的最小值即可。
线段树维护它写着写着,代码就5.6k了
#include<cstdio> #include<algorithm> #include<cstring> #include<cstdlib> using namespace std; const int INF=1313331331; int T,n,a[200002],lgg[200002],fa[22][200002],q[200002],len,tax[200002],sa[200002],rk[200002],cnt; int h[22][200002],Min[22][200002],las[200002],tp[200002],head[200002],x,y; unsigned long long has[200002],cf[200002]; long long w[200002]; typedef struct{ int to,nex; }P; P p[200002]; typedef struct{ int Max,Min,f1,f2; }XDS; XDS xds[800002]; void add(int x,int y){ p[++cnt].to=y;p[cnt].nex=head[x];head[x]=cnt; } bool cmp(int x,int y){ return (a[x]<a[y]); } inline bool pd(int x,int y,int l,int r){ if (x<l)return (has[y]-has[x-1])*cf[l-x]==(has[r]-has[l-1]); else return (has[y]-has[x-1])==(has[r]-has[l-1])*cf[x-l]; } inline int minh(int x,int y){ int len=y-x+1; return min(h[lgg[len]][x],h[lgg[len]][y-(1<<lgg[len])+1]); } inline int bj(int x,int y){ int lef=0,righ=min(n-x+1,n-y+1),mid; while(lef<righ) { mid=(lef+righ+1)/2; if (pd(x,x+mid-1,y,y+mid-1))lef=mid;else righ=mid-1; } return lef; } int read(){ int f=0;char ch=getchar(); while(ch<'0' || ch>'9')ch=getchar(); while(ch>='0' && ch<='9'){f=f*10+ch-48;ch=getchar();} return f; } void pushdown(int root){ if (xds[root].f1) { if (xds[root].f1>xds[root*2].Max)xds[root*2].Max=xds[root].f1; if (xds[root].f1>xds[root*2+1].Max)xds[root*2+1].Max=xds[root].f1; if (!xds[root*2].f1 || xds[root].f1>xds[root*2].f1)xds[root*2].f1=xds[root].f1; if (!xds[root*2+1].f1 || xds[root].f1>xds[root*2+1].f1)xds[root*2+1].f1=xds[root].f1; xds[root].f1=0; } if (xds[root].f2) { if (xds[root].f2<xds[root*2].Min)xds[root*2].Min=xds[root].f2; if (xds[root].f2<xds[root*2+1].Min)xds[root*2+1].Min=xds[root].f2; if (!xds[root*2].f2 || xds[root].f2<xds[root*2].f2)xds[root*2].f2=xds[root].f2; if (!xds[root*2+1].f2 || xds[root].f2<xds[root*2+1].f2)xds[root*2+1].f2=xds[root].f2; xds[root].f2=0; } } void build(int root,int begin,int end){ xds[root].f1=xds[root].f2=0; if (begin==end) { xds[root].Max=-1e9;xds[root].Min=1e9; return; } int mid=(begin+end)/2; build(root*2,begin,mid);build(root*2+1,mid+1,end); xds[root].Max=max(xds[root*2].Max,xds[root*2+1].Max); xds[root].Min=min(xds[root*2].Min,xds[root*2+1].Min); } void chaxun(int root,int begin,int end,int wz){ if (begin>wz || end<wz)return; if (begin==end) { x=xds[root].Max;y=xds[root].Min;return; } int mid=(begin+end)/2;pushdown(root); chaxun(root*2,begin,mid,wz);chaxun(root*2+1,mid+1,end,wz); } void gxmax(int root,int begin,int end,int begin2,int end2,int z){ if (begin>end2 || end<begin2)return; if (begin>=begin2 && end<=end2) { if (z>xds[root].Max)xds[root].Max=z; if (!xds[root].f1 || z>xds[root].f1)xds[root].f1=z; return; } int mid=(begin+end)/2;pushdown(root); gxmax(root*2,begin,mid,begin2,end2,z);gxmax(root*2+1,mid+1,end,begin2,end2,z); xds[root].Max=max(xds[root*2].Max,xds[root*2+1].Max); } void gxmin(int root,int begin,int end,int begin2,int end2,int z){ if (begin>end2 || end<begin2)return; if (begin>=begin2 && end<=end2) { if (z<xds[root].Min)xds[root].Min=z; if (!xds[root].f2 || z<xds[root].f2)xds[root].f2=z; return; } int mid=(begin+end)/2;pushdown(root); gxmin(root*2,begin,mid,begin2,end2,z);gxmin(root*2+1,mid+1,end,begin2,end2,z); xds[root].Min=min(xds[root*2].Min,xds[root*2+1].Min); } int main() { for (int i=1;i<=200000;i++) for (int j=0;(1<<j)<=i;j++)lgg[i]=j; cf[0]=1; for (int i=1;i<=200000;i++)cf[i]=cf[i-1]*INF; T=read(); while(T--) { n=read();len=0; for (int i=1;i<=n;i++)a[i]=read(); for (int i=n;i>=1;i--) { while(len && a[i]>=a[q[len]])len--; if (len)fa[0][i]=q[len];else fa[0][i]=0; q[++len]=i; if (fa[0][i])w[i]=(long long)a[i]*(fa[0][i]-i)+w[fa[0][i]]; else w[i]=(long long)a[i]*(n-i+1); } for (int i=1;i<=17;i++) for (int j=1;j<=n;j++) fa[i][j]=fa[i-1][fa[i-1][j]]; for (int i=1;i<=n;i++) { has[i]=has[i-1]+cf[i-1]*a[i]; sa[i]=i; } sort(sa+1,sa+n+1,cmp); rk[sa[1]]=1; for (int i=2;i<=n;i++) if (a[sa[i]]==a[sa[i-1]])rk[sa[i]]=rk[sa[i-1]];else rk[sa[i]]=rk[sa[i-1]]+1; for (int i=1;i<=17;i++) { for (int j=0;j<=n;j++){las[j]=rk[j];tax[j]=0;head[j]=-1;} cnt=0; for (int j=1;j<=n;j++) { if (j+(1<<i-1)>n)tp[j]=0;else tp[j]=j+(1<<i-1); tax[rk[j]]++;add(rk[tp[j]],j); } for (int j=1;j<=n;j++)tax[j]+=tax[j-1]; for (int j=n;j>=0;j--) for (int k=head[j];k!=-1;k=p[k].nex) sa[tax[rk[p[k].to]]--]=p[k].to; rk[sa[1]]=1; for (int j=2;j<=n;j++) if (las[sa[j]]==las[sa[j-1]] && las[tp[sa[j]]]==las[tp[sa[j-1]]])rk[sa[j]]=rk[sa[j-1]];else rk[sa[j]]=rk[sa[j-1]]+1; } build(1,1,n); for (int i=1;i<=n;i++)Min[0][i]=sa[i]; for (int i=1;i<n;i++)h[0][i]=bj(sa[i],sa[i+1]); for (int i=1;i<=17;i++) for (int j=1;j<=n;j++) { if (j+(1<<i-1)<=n)h[i][j]=min(h[i-1][j],h[i-1][j+(1<<i-1)]); if (j+(1<<i-1)<=n)Min[i][j]=min(Min[i-1][j],Min[i-1][j+(1<<i-1)]); } long long ans=0; for (int i=1;i<=n;i++) { int Max=0; chaxun(1,1,n,rk[i]); if (x>=1 && x<=n && x<rk[i])Max=max(Max,minh(x,rk[i]-1)); if (y>=1 && y<=n && y>rk[i])Max=max(Max,minh(rk[i],y-1)); y=i+Max; if (y<=n) { int x=i; for (int j=17;j>=0;j--) if (fa[j][x]!=0 && fa[j][x]<=y)x=fa[j][x]; if (fa[0][x])ans+=(long long)a[x]*(fa[0][x]-y)+w[fa[0][x]]; else ans+=(long long)a[x]*(n-y+1); } if (rk[i]>1)gxmin(1,1,n,1,rk[i]-1,rk[i]); if (rk[i]<n)gxmax(1,1,n,rk[i]+1,n,rk[i]); } printf("%lld ",ans); } return 0; }