枚举 ---- D. Zigzags[ Educational Codeforces Round 94 (Rated for Div. 2)]思维枚举优化4重循环

D. Zigzags


题目大意:就是给你 i < j < k < l 并 且 a j = a l & & a i = a k i<j<k<l并且a_j=a_l \&\& a_i=a_k i<j<k<laj=al&&ai=ak,求满足(i,j,k,l)的四元组有多少对


解题思路:1.很明显我们最暴力的做法是 O ( n 4 ) O(n^4) O(n4)去枚举,因为题目的数据只有3000,可以预估的复杂度在 O ( n 2 ) O(n^2) O(n2)左右,那么实际上我们可以只枚举i,
j,k,l其中两个

2.我们可以枚举k和i,注意是k和i就是先枚举k再逆序去枚举i,接下来就是如何把j和l统计进去
3.根据乘法原理每个总数就是 s u m j ∗ s u m l sum_j*sum_l sumjsuml,但是是每一个k和i都要跑一遍吗?不用.用dp的思想,设dp[i][j],就是从j到i满足条件的四元组的个数,dp[k][i]其实可以用dp[k][i+1]的基础上加上了a[i]这个数在[k,n]这个区间内和它相同的数的个数
那么对于每个k我们预处理[k,n]每个数出现的次数然后按照上面的思路转移就好了


void solve(){
	ll ans=0,sum;//统计所有次数。
	rep(i,1,n){
		//我们确定第三个编号,统计第四个编号出现的次数。
		sum=0;
		memset(cnt,0,sizeof(cnt));//初始化。
		rep(j,i+1,n)cnt[a[j]]++;//统计第三个编号之后每个元素出现次数
		per(j,i-1,1){
			if(a[j]==a[i]){
				//说明找到第一个编号,我们统计之间有多少的方案数。
				ans+=sum;
			}
			sum+=cnt[a[j]];//统计第二个编号的方案数。
		}
	}
	cout<<ans<<endl;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值