CodeForces 1400 D-Zigzags 枚举+思维+前缀维护

在这里插入图片描述
题意:给定你n个数,然后让你确定一个四元组(i,j,k,l),使得a[i] == a[k]并且a[j] == a[l]。n <= 3000。
数据范围不大,想到枚举可以解决,但是最多是一个O(n^2)的,但是四元组我们直接枚举会超时。假如想要枚举i和k的话,我们需要两层遍历找到能使得i等于k的位置,但是这时候j和l还没确定下来,我们最好需要在一层循环解决,也是超时。
因为i和k可以说是具有相同属性的一组数,假如我们枚举j和k,这是他们所确定的属性可以看做是不同的。我们只需要去找到j前面的k,和k后面的j,即可完成,我们这时用一个二位数组pre[pos][num],来维护pos位置前的数值等于num的位置有多少个。这样就可以在O(n^2)的枚举的同时,完成答案的更新。
ps:因为我维护的这个pre数组没有记录当前位置的数,故遇到假如当前枚举的a[k] == a[j]的话,答案会多加上一个数,这个需要更新答案是特判一下即可。

代码:

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int MAXN = 3e3+7;
ll pre[MAXN][MAXN];
//枚举j和k的位置 然后去找剩下的位置对应的次数 
//用一个pre数组提前预处理一下 
//可以O(n^2) 处理
//把四层循环变为了两重循环
int a[MAXN];

int main()
{
	int T;
	scanf("%d",&T);
	while(T--){
		int n;
		scanf("%d",&n);
		memset(pre,0,sizeof(pre));
		for(int i = 1;i <= n;i ++) scanf("%d",&a[i]);
		for(int i = 2;i <= n+1;i ++){
			for(int j = i-1;j >= 1;j --)
				pre[i][a[j]]++;
		}
		ll ans = 0;
		for(int j = 2;j < n-1;j ++){
			for(int k = j + 1;k < n;k ++){
				ll t1 = pre[j][a[k]];
				ll t2 = pre[n+1][a[j]]-pre[k][a[j]];//前面的个数记录 因此这个地方是减去
				if(a[k] == a[j]) t2--;//这里因为我的pre数组没记录挡墙这个位置上 所以这个位置a[k] == a[j]的话,答案会多加
				ans += t1 * t2;
			}
		}
		printf("%lld\n",ans);
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值