luogu P4065 [JXOI2017]颜色 |随机化+前缀和

题目描述

可怜有一个长度为 n 的正整数序列 Ai,其中相同的正整数代表着相同的颜色。

现在可怜觉得这个序列太长了,于是她决定选择一些颜色把这些颜色的所有位置都删去。

删除颜色 i 可以定义为把所有满足 Aj = i 的位置 j 都从序列中删去。

然而有些时候删去之后,整个序列变成了好几段,可怜不喜欢这样,于是她想要知道有多少种删去颜色的方案使得最后剩下来的序列非空且连续。

例如颜色序列 {1, 2, 3, 4, 5},删除颜色 3 后序列变成了 {1, 2} 和 {4, 5} 两段,不满足条件。而删除颜色 1 后序列变成了 {2, 3, 4, 5},满足条件。

两个方案不同当且仅当至少存在一个颜色 i 只在其中一个方案中被删去。

输入格式

第一行输入一个整数 T 表示数据组数。每组数据第一行输入一个整数 n 表示数列长度。第二行输入 n 个整数描述颜色序列。

输出格式

对于每组数据输出一个整数表示答案。


给每个颜色rand()一个值,使得所有相同颜色之和为0

维护前缀和,用map找左边出现过的一样的值,即可以相减为0的值

#include<map>
#include<ctime>
#include<cstdlib>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define ll long long
const int N=3e5+10;
inline ll read(ll x=0){
	char c=getchar();
	while(c<'0'||c>'9')c=getchar();
	while('0'<=c&&c<='9'){  x=(x<<3)+(x<<1)+c-'0'; c=getchar(); }
	return x;
}
#define Rand() (((ll)rand())<<1)-RAND_MAX
ll n,a[N],Max[N],sum[N];
map<ll,int>vis;
signed main(){
	srand(time(0)); 
	register int i;
	register ll op,qz,ans;
	for(int T=read();T;T--){
		n=read(); 
		for(i=1;i<=n;i++)a[i]=read(),Max[a[i]]=i;
		qz=0,ans=0; vis[qz]=1;
		for(i=1;i<=n;i++){
			op= (Max[a[i]]^i) ? Rand() : -sum[a[i]];
			sum[a[i]]+=op; qz+=op;
			ans+=vis[qz]; vis[qz]++;
		}
		printf("%lld\n",ans);
		vis.clear();
		memset(Max,0,sizeof(Max));
		memset(sum,0,sizeof(sum));
	}
	return 0;
}
}
posted @ 2019-12-07 13:27  白木偶君  阅读(118)  评论(0编辑  收藏  举报