题解
题目中的第一个问题让我们求一个三元组( i , j , k)满足i < j < k 并且 f( j ) < f ( i ) 并且 f( j )< f ( k );
也就是让我们求逆序对。
我们不妨枚举中间的数j 先计算出j左边比f (j)大的数(j的逆序对)
再从后往前枚举 计算j右边比f(j)大的数
我们可以用树状数组记录每个数出现了多少次,每次枚举结束时把当前点加入到我们的树状数组里
最后根据乘法原理 把左边比当前数大的数的数量乘上右边大的数的数量即可
第二个问题同理
所以这道题实际考察的是树状数组求逆序对。
我们发现这道题的值域非常小是2e5,所以不需要离散化。
不然的话还得离线离散化,排序去重二分,啊这还得排序。
那不是直接归并排序来的更快点嘛。。。
代码如下:
#include<bits/stdc++.h> using namespace std; const int N = 200010; int n; typedef long long LL; int a[N]; int lower[N],Greater[N]; int tr[N]; int lowbit(int x) { return x & -x; } int sum(int x) { int res = 0; for(int i = x; i; i -= lowbit(i)) res += tr[i]; return res; } void add(int x,int c) { for(int i = x; i <= n; i += lowbit(i)) tr[i] += c; } int main() { cin >> n; for(int i = 1; i <= n; ++ i) scanf("%d",&a[i]); for(int i = 1; i <= n; ++ i) { int y = a[i]; lower[i] = sum(y - 1); //在i之前比ai小的数; Greater[i] = sum(n) - sum(y); //在i之前比ai大的数; add(y,1); } LL res1 = 0,res2 = 0; memset(tr,0,sizeof tr); for (int i = n; i >= 1; -- i) { int y = a[i]; res1 += Greater[i] * (LL)(sum(n) - sum(y)); res2 += lower[i] * (LL)(sum(y - 1)); add(y, 1); } printf("%lld %lld ", res1, res2); return 0; }