题意
给一个序列进行栈操作,从左到右入栈,若当前入栈元素等于栈顶元素则栈顶元素出栈,否则当前元素入栈。若进行完操作后栈为空,这说这个序列是可以被消除的。
给你一个长度为nnn的序列aaa,问aaa有多少子串是可以被消除的。
题解
定义fif_ifi表示序列ai,ai+1,...,ana_i,a_{i+1},...,a_nai,ai+1,...,an有多少可以被消除的子串
那么fi=fj+1+1f_i=f_{j+1}+1fi=fj+1+1,jjj是使得ai,ai+1,...,aja_i,a_{i+1},...,a_jai,ai+1,...,aj能够被消除的最小的jjj
如果不存在此jjj,那么fi=0f_i=0fi=0
那么Ans=∑i=1nfiAns=\sum_{i=1}^nf_iAns=∑i=1nfi
考虑如何对于每一个iii求出这个jjj
记NxiNx_iNxi表示此jjj,那么如果aNxi+1+1=aia_{Nx_{i+1}+1}=a_iaNxi+1+1=ai,则Nxi=Nxi+1+1Nx_i=Nx_{i+1}+1Nxi=Nxi+1+1
否则再判断aNxNxi+1+1+1=aia_{Nx_{Nx_{i+1}+1}+1}=a_iaNxNxi+1+1+1=ai,则Nxi=NxNxi+1+1+1Nx_i=Nx_{Nx_{i+1}+1}+1Nxi=NxNxi+1+1+1
如此递归直到找到一个NxkNx_kNxk或者Nxk+1>nNx_k+1>nNxk+1>n为止
这样显然耗时显然是巨大的,而我们每次又只要找aia_iai
考虑设Nyi,xNy_{i,x}Nyi,x表示使得ai,ai+1,...,aj−1a_i,a_{i+1},...,a_{j-1}ai,ai+1,...,aj−1能够被消除的最小的jjj且aj=xa_j=xaj=x
那么Nxi=Nyi+1,aiNx_i=Ny_{i+1,a_i}Nxi=Nyi+1,ai,如果ai−1≠aia_{i-1}\neq a_iai−1=ai,那么ai−1a_{i-1}ai−1跳NxNxNx就一定会跳到Nyi+1,ai+1Ny_{i+1,a_i}+1Nyi+1,ai+1处再进行判断
那么我们可以直接令Nyi=NyNxi+1Ny_i=Ny_{Nx_i+1}Nyi=NyNxi+1即可(这里C++C++C++对mapmapmap使用swapswapswap可以做到O(1)O(1)O(1))
此时ai,ai+1,...,aNxia_i,a_{i+1},...,a_{Nx_i}ai,ai+1,...,aNxi是可以被消除的,所以Nyi,aNxi+1=Nxi+1Ny_{i,a_{Nx_i+1}}=Nx_i+1Nyi,aNxi+1=Nxi+1
然后也要把aia_iai加进去,即Nyi,ai=iNy_{i,a_i}=iNyi,ai=i
时间复杂度O(nlogn)O(n\log n)O(nlogn)
#include<bits/stdc++.h>
#define fp(i,a,b) for(register int i=a,I=b+1;i<I;++i)
#define fd(i,a,b) for(register int i=a,I=b-1;i>I;--i)
#define file(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
char ss[1<<17],*A=ss,*B=ss;
inline char gc(){return A==B&&(B=(A=ss)+fread(ss,1,1<<17,stdin),A==B)?-1:*A++;}
template<class T>inline void sd(T&x){
char c;T y=1;while(c=gc(),(c<48||57<c)&&c!=-1)if(c==45)y=-1;x=c-48;
while(c=gc(),47<c&&c<58)x=x*10+c-48;x*=y;
}
const int N=3e5+5,M=N<<1,inf=~0u>>1;
typedef long long ll;
typedef int arr[N];
int n,a[N],Nx[N];ll f[N];
map<int,int>Ny[N];
inline void sol(){
sd(n);
fp(i,1,n){
sd(a[i]);
Ny[i].clear();
Nx[i]=-1;f[i]=0;
}
Ny[n+1].clear();f[n+1]=0;
int p;ll ans=0;
fd(i,n,1){
if(Ny[i+1].count(a[i])){
Nx[i]=p=Ny[i+1][a[i]];
swap(Ny[i],Ny[p+1]);
if(p!=n)Ny[i][a[p+1]]=p+1;
}
Ny[i][a[i]]=i;
}
fd(i,n,1)if(~Nx[i]){
f[i]=f[Nx[i]+1]+1;
ans+=f[i];
}
printf("%lld\n",ans);
}
int main(){
#ifndef ONLINE_JUDGE
file("s");
#endif
int q;
scanf("%d",&q);
while(q--)sol();
return 0;
}