Codeforces Round #789 (Div. 2) C

写个题解气吐了,卡在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;
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值