CodeForces - 1400D Zigzags(简单dp)

题目链接:点击查看

题目大意:给出一个长度为 n 的数列 a ,现在要求找到满足条件的四元对 ( i , j , k , l ) 的个数:

  1. 1 <= i < j < k < l <= n
  2. a[ i ] == a[ k ] && a[ j ] == a[ l ]

题目分析:n 只有 3000 ,显然支持 n * n * logn 的时间复杂度,所以可以枚举四元对中其中的两个位置,然后去计算剩下的两个位置中有多少个符合条件的,基于此,我们可以设计两个简单的 dp 辅助实现,dp1[ i ][ j ] 代表的是 [ 1 , i ] 区间内,j 出现的次数,相似的,dp2[ i ][ j ] 代表的是 [ i , n ] 区间内,j 出现的次数,这样我们就可以 n * n 去枚举 j 和 k ,对于每一对 j 和 k ,我们都可以直接得出 k 后面有多少个等于 a[ j ] 的个数,以及 j 前面有多少个等于 a[ k ] 的个数了,其乘积的累加和便是答案

代码:
 

#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
using namespace std;
  
typedef long long LL;
  
typedef unsigned long long ull;
  
const int inf=0x3f3f3f3f;

const int N=3e3+100;

LL a[N],dp1[N][N],dp2[N][N];//dp1[i][j]:[1,i]内有多少个j,dp2[i][j]:[i,n]内有多少个j 

int main()
{
#ifndef ONLINE_JUDGE
//  freopen("data.in.txt","r",stdin);
//  freopen("data.out.txt","w",stdout);
#endif
//  ios::sync_with_stdio(false);
	int w;
	cin>>w;
	while(w--)
	{
		int n;
		scanf("%d",&n);
		for(int i=1;i<=n;i++)
			scanf("%lld",a+i);
		for(int i=1;i<=n;i++)
			dp1[0][i]=dp2[n+1][i]=0;
		for(int i=1;i<=n;i++)
		{
			for(int j=1;j<=n;j++)
				dp1[i][j]=dp1[i-1][j];
			dp1[i][a[i]]++;
		}
		for(int i=n;i>=1;i--)
		{
			for(int j=1;j<=n;j++)
				dp2[i][j]=dp2[i+1][j];
			dp2[i][a[i]]++;
		}
		LL ans=0;
		for(int j=1;j<=n;j++)
			for(int k=j+1;k<=n;k++)
				ans+=dp1[j-1][a[k]]*dp2[k+1][a[j]];
		printf("%lld\n",ans);
	}
















    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_45458915/article/details/108237388
今日推荐