[ABC318E] Sandwiches 题解

一开始考虑枚举 \(i\)\(k\) 来统计,发现需要 \(O(n^2)\) 的时间复杂度。

因此考虑枚举 \(j\),我们可以用 \(l_x\) 表示满足 \(i<j,a_i=x\) 的数量,用 \(r_x\) 表示满足 \(j<k,a_k=x\) 的数量。

那么会发现对于每一个 \(j\),它的贡献应为 \(\sum_{x=1,x \not = a_j}^n l_xr_x\),注意到 \(a_j\) 只有一项,所以考虑容斥,将这一项单独提出来,那么贡献就变成了 \((\sum_{x=1}^n l_xr_x)-l_{a_j}r_{a_j}\),因此我们可以先处理出 \(\sum_{x=1}^n l_xr_x\),在每次 \(j\) 移动的时候修改贡献即可。预处理时间复杂度 \(O(n)\),修改为 \(O(1)\),每次统计答案为 \(O(1)\),总时间复杂度 \(O(n)\),足以通过本题。

#include <cstdio>

const int N=3e5+5;

int n;
int a[N];
int l[N],r[N];
long long ans,sum;

int main() {
	scanf("%d",&n);
	for(int i=1;i<=n;i++) {
		scanf("%d",&a[i]);
		if(i==1) l[a[i]]++;//初始化l和r
		else if(i!=2) r[a[i]]++;
	}
	for(int i=1;i<=n;i++) sum+=(1ll*l[i]*r[i]);//预处理
	for(int j=2;j<n;j++) {
		ans+=(sum-1ll*l[a[j]]*r[a[j]]);//统计答案
		++l[a[j]];sum+=r[a[j]];//修改
		--r[a[j+1]];sum-=l[a[j+1]];
	}
	printf("%lld\n",ans);
	return 0;
}
posted @ 2023-09-03 10:37  Scorilon  阅读(20)  评论(0)    收藏  举报