Portal:GYM-102028H
题意:
求所有本质不同子序列的最大值的和。
思路:
参考本质不同的子串做法处理本质不同子序列:后缀数组, h e i g h t height height部分的子串就是没有贡献的子串。
考虑以位置 i i i 为左端点的所有子串答案的求法,找到 i i i 后第一个大于 a [ i ] a[i] a[i] 的位置 P o s Pos Pos 。 s u m [ i ] = a [ i ] ∗ ( P o s − i ) + s u m [ P o s ] sum[i]=a[i]*(Pos-i)+sum[Pos] sum[i]=a[i]∗(Pos−i)+sum[Pos]
用单调栈可求 i i i 右侧第一个大于 a [ i ] a[i] a[i] 的位置 N e x t [ i ] Next[i] Next[i] 。 s u m sum sum 数组也可预处理出来。
答案的统计:从 1 − n 1-n 1−n遍历,若 h e i g h t [ r a n k [ i ] ] height[rank[i]] height[rank[i]] 为 0 0 0 , 则当前位置对答案的贡献就是 s u m [ i ] sum[i] sum[i] 。若不为 0 0 0 ,用线段树等方法求出 i i i 到 i + h e i g h t [ r a n k [ i ] ] − 1 i+height[rank[i]]-1 i+height[rank[i]]−1 最大值的位置 M x p [ i ] Mxp[i] Mxp[i] ,当前位置对答案的贡献就为 s u m [ N e x t [ M x p [ i ] ] ] + a [ M x p [ i ] ] ∗ ( N e x t [ M x p [ i ] ] − i − h e i g h t [ r a n k [ i ] ] ) sum[Next[Mxp[i]]]+a[Mxp[i]]*(Next[Mxp[i]]-i-height[rank[i]]) sum[Next[Mxp[i]]]+a[Mxp[i]]∗(Next[Mxp[i]]−i−height[rank[i]])
最后就是多组数据的处理,若将 N e x t [ i ] Next[i] Next[i] 不存在时赋值为 n + 1 n+1 n+1 ,需要将 a [ n + 1 ] a[n+1] a[n+1] 清零!!!死在这里死了好久枯了。
#include
#define N 200005
using namespace std;
typedef long long ll;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-' ) f=-1;ch=getchar();}
while(isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
}
int T,n,tot,m;
int sa[N],height[N],Rank[N],Hash[N],x[N],y[N],a[N],c[N],Next[N],Mxp[N];
ll sum[N];
ll Ans;
class Seg_Tree{
public:
int l,r,mxp;
}e[N<<2];
void Build(int p,int l,int r)
{
e[p].l=l,e[p].r=r;
if(l==r) {
e[p].mxp=l;
return;
}
int mid=l+r>>1;
Build(p<<1,l,mid);Build(p<<1|1,mid+1,r);
e[p].mxp=a[e[p<<1].mxp]>=a[e[p<<1|1].mxp]?e[p<<1].mxp:e[p<<1|1].mxp;
}
int Find_Max(int p,int x,int y)
{
int l=e[p].l,r=e[p].r;
if(l==x&&r==y) return e[p].mxp;
int mid=l+r>>1;
if(y<=mid) return Find_Max(p<<1,x,y);
if(x>mid) return Find_Max(p<<1|1,x,y);
int lm=Find_Max(p<<1,x,mid),rm=Find_Max(p<<1|1,mid+1,y);
return a[lm]>=a[rm]?lm:rm;
}
int Find(int x)
{
int l=1,r=tot,rtn=0;
while(l<=r)
{
int mid=l+r>>1;
if(Hash[mid]>=x) rtn=mid,r=mid-1;
else l=mid+1;
}
return rtn;
}
void Init()
{
n=read();Ans=0;a[n+1]=0;
for(int i=1;i<=n;i++) Hash[i]=a[i]=read();
sort(Hash+1,Hash+1+n);
tot=unique(Hash+1,Hash+1+n)-Hash-1;
for(int i=1;i<=n;i++) a[i]=Find(a[i]);
}
void Build_Sa()
{
m=tot+1;
for(int i=1;i<=m;i++) c[i]=0;
for(int i=1;i<=n;i++) c[x[i]=a[i]]++;
for(int i=1;i<=m;i++) c[i]+=c[i-1];
for(int i=n;i;i--) sa[c[x[i]]--]=i;
for(int k=1;k<=n;k<<=1)
{
int p=0;
for(int i=n-k+1;i<=n;i++) y[++p]=i;
for(int i=1;i<=n;i++) if(sa[i]>k) y[++p]=sa[i]-k;
for(int i=1;i<=m;i++) c[i]=0;
for(int i=1;i<=n;i++) c[x[y[i]]]++;
for(int i=1;i<=m;i++) c[i]+=c[i-1];
for(int i=n;i;i--) sa[c[x[y[i]]]--]=y[i];
swap(x,y);x[sa[1]]=1;p=1;
for(int i=2;i<=n;i++)
x[sa[i]]=y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k]?p:++p;
if(p>=n) break; m=p;
}
}
void Get_Height()
{
for(int i=1;i<=n;i++) Rank[sa[i]]=i;
int k=0;
for(int i=1;i<=n;i++)
{
if(k) k--;
int j=sa[Rank[i]-1];
while(a[i+k]==a[j+k]) k++;
height[Rank[i]]=k;
}
for(int i=1;i<=n;i++)
Mxp[i]=height[Rank[i]]==0?0:Find_Max(1,i,i+height[Rank[i]]-1);
}
stack<int>st;
void Get_Next()
{
while(!st.empty()) st.pop();
for(int i=1;i<=n;i++) Next[i]=n+1;
for(int i=1;i<=n;i++)
{
while(!st.empty()&&a[st.top()]<a[i])
{
Next[st.top()]=i;
st.pop();
}
st.push(i);
}
sum[n+1]=0;
for(int i=1;i<=n;i++) sum[i]=1LL*Hash[a[i]]*(Next[i]-i);
for(int i=n;i;i--) sum[i]+=sum[Next[i]];
}
void Solve()
{
for(int i=1;i<=n;i++)
{
if(!Mxp[i]) Ans+=sum[i];
else
Ans+=sum[Next[Mxp[i]]]+1LL*Hash[a[Mxp[i]]]*(Next[Mxp[i]]-i-height[Rank[i]]);
}
printf("%lld\n",Ans);
}
int main()
{
T=read();
while(T--)
{
Init();
Build_Sa();
Build(1,1,n);
Get_Height();
Get_Next();
Solve();
}
return 0;
}