写个题解气吐了,卡在b2,后面半小时看的c,应该比较适合我的口味www
题意:给定一个全排列,要求你找到四个下标满足a,b,c,d满足pa<pc并且pb>pd;
思路:首先我们可以思路变成连边,将数字小的连向数字大的,那我们对于任意两个位置
b,c。我们要考虑什么它可以找到多少满足条件的a,d;
对于b节点,我们应该在c的后面找有多少个小于它的点;
对于c节点,我们应该在b的前面找有多少个小于它的点;
于是我们可以用o(n^2)先处理出前缀和;
然后在o(n^2)选择任意两个不同节点,用前缀和o(1),查询每两个点的贡献即可;
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=5010;
int a[N],head[N][N],tail[N][N];
int main(){
int t;
cin>>t;
while(t--){
int n;
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++)tail[i][j]=0,head[i][j]=0;
for(int j=i+1;j<=n;j++){
if(a[j]<a[i])tail[i][j]=1;
}
for(int j=1;j<i;j++){
if(a[j]<a[i])head[i][j]=1;
}
}//处理该点是否小于它
for(int i=1;i<=n;i++){
for(int j=1;j<=i-1;j++){
head[i][j]+=head[i][j-1];
}
for(int j=i+1;j<=n;j++){
tail[i][j]+=tail[i][j-1];
}
}//处理前缀和
ll ans=0;
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
int hou=tail[i][n]-tail[i][j];
int qian=head[j][i-1];
ans+=hou*qian;
}
}
cout<<ans<<endl;
}
}