题意
给出一组数:
寻找四元组的个数
(i,j,k,l)其中a[i]=a[k],并且a[j]=a[l]
且 1 <= i < j < k < l <= n ;
思路
四个数 分别为 a1 b1 a2 b2 其中 a1=a2 b1=b2
先枚举b1的位置(从 i = 2开始,因为前面必须有数当a1)
然后从 j = i+1位置开始遍历到j=n,找与b1相等的数
若num[ i ] = num[ j ],则代表找到了 b2,那么此时更新答案ans
那么怎么更新答案呢
我们在 j 开始遍历时,记录每一个位置的数在前面出现的次数的总和sum
因为 一个数前面出现过几次 就代表 有几组 (a1, a2)
在b1 b2确定之后(即num [ i ] =num [ j ]时) i+1 ~ j-1之间的数都可以是a2 那么每一个a2 又可能有多个a1与其对应(a2 这个数在之前出现过几次 就有几个a1 与其对应) ,所以sum就是 每一对确定的 b1 b2 对应的合题意的四元组的组数
综上:
枚举b1 对于每一个b1 ,初始化sum=0 ,遍历找b2,遍历的同时,记录可能的(a1,a2)的组数sum 成功找到一个 b2,就更新答案 ans+=sum; 遍历完成后,更新b1这个数的出现次数
代码
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <vector>
#define mm 1000000007
using namespace std;
typedef long long ll;
int a[3010],cnt[3010];///a:原数组 cnt:次数数组 目前 i 出现过几次
///a1 b1 a2 b2
int main()
{
int t,x;
scanf("%d",&t);
while(t--)
{
scanf("%d",&x);
for(int i=1;i<=x;i++)
{
scanf("%d",&a[i]);
cnt[i]=0;
}
ll ans=0,sum=0;
cnt[a[1]]=1;///a[1]这个元素出现过1次
for(int i=2;i<x;i++)///枚举b1
{
sum=0;///sum为对于每一个固定的i 合题意的组数
for(int j=i+1;j<=x;j++)///枚举a2
{
if(a[i]==a[j])ans+=sum;///找到b2 更新答案
sum+=cnt[a[j]];///前面a[j] 出现cnt【】次,就有cnt组
}
cnt[a[i]]++;
}
printf("%lld\n",ans);
}
return 0;
}