[Codeforces1223F]Stack Exterminable Arrays

题意

给一个序列进行栈操作,从左到右入栈,若当前入栈元素等于栈顶元素则栈顶元素出栈,否则当前元素入栈。若进行完操作后栈为空,这说这个序列是可以被消除的。

给你一个长度为 n n 的序列 a a ,问 a a 有多少子串是可以被消除的。


题解

定义 f i f_i 表示序列 a i , a i + 1 , . . . , a n a_i,a_{i+1},...,a_n 有多少可以被消除的子串

那么 f i = f j + 1 + 1 f_i=f_{j+1}+1 j j 是使得 a i , a i + 1 , . . . , a j a_i,a_{i+1},...,a_j 能够被消除的最小的 j j

如果不存在此 j j ,那么 f i = 0 f_i=0

那么 A n s = i = 1 n f i Ans=\sum_{i=1}^nf_i

考虑如何对于每一个 i i 求出这个 j j

N x i Nx_i 表示此 j j ,那么如果 a N x i + 1 + 1 = a i a_{Nx_{i+1}+1}=a_i ,则 N x i = N x i + 1 + 1 Nx_i=Nx_{i+1}+1

否则再判断 a N x N x i + 1 + 1 + 1 = a i a_{Nx_{Nx_{i+1}+1}+1}=a_i ,则 N x i = N x N x i + 1 + 1 + 1 Nx_i=Nx_{Nx_{i+1}+1}+1

如此递归直到找到一个 N x k Nx_k 或者 N x k + 1 > n Nx_k+1>n 为止

这样显然耗时显然是巨大的,而我们每次又只要找 a i a_i

考虑设 N y i , x Ny_{i,x} 表示使得 a i , a i + 1 , . . . , a j 1 a_i,a_{i+1},...,a_{j-1} 能够被消除的最小的 j j a j = x a_j=x

那么 N x i = N y i + 1 , a i Nx_i=Ny_{i+1,a_i} ,如果 a i 1 a i a_{i-1}\neq a_i ,那么 a i 1 a_{i-1} N x Nx 就一定会跳到 N y i + 1 , a i + 1 Ny_{i+1,a_i}+1 处再进行判断

那么我们可以直接令 N y i = N y N x i + 1 Ny_i=Ny_{Nx_i+1} 即可(这里 C + + C++ m a p map 使用 s w a p swap 可以做到 O ( 1 ) O(1)

此时 a i , a i + 1 , . . . , a N x i a_i,a_{i+1},...,a_{Nx_i} 是可以被消除的,所以 N y i , a N x i + 1 = N x i + 1 Ny_{i,a_{Nx_i+1}}=Nx_i+1

然后也要把 a i a_i 加进去,即 N y i , a i = i Ny_{i,a_i}=i

时间复杂度 O ( n log n ) O(n\log n)

#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;
}

猜你喜欢

转载自blog.csdn.net/BeNoble_/article/details/102333058