题目描述
撷来一缕清风飘渺
方知今日书信未到
窗外三月天霁垂柳新长枝条
风中鸟啼犹带欢笑
——《清风醉梦》
小奇望着青天中的悠悠白云,开始了无限的遐想,在它的视野中,恰好有n朵高度不同的白云排成一排,他想从左到右选出四朵白云a,b,c,d,使得h_a<h_b<h_d<h_c,即看起来像是彩虹的形状!它想知道有多少种方案数。
输入
第一行包括1个整数n。
第二行包括n个整数,第i个正数表示h_i,保证这n个整数是n的一个全排列。
输出
输出一个整数表示答案。(mod 16777216)
样例输入
5 1 5 3 2 4
样例输出
0
题目意思为给一个序列,要我们求一个四元组abdc,意思是a<b<d, d>c,也就是说要求abd是递增的然后c比d小的四元组的个数,我们可以先考虑一下用abxx的个数,abxx意思为b>a然后后面的数大于b的四元组的个数,然后我们再求一下满足abcd的四元组的个数,最后abxx-abcd就是我们要求的答案了,求abxx和abcd的个数可以用树状数组来求,abxx好求,求用b前面比他小的个数乘上后面比他大的数的个数里面选两个就可以了,abcd的个数可以用c前面ab的个数乘上后面比他大的数就可以了,也是用树状数组维护,不过维护的时候a[i]的值是ab的个数。
AC代码:
#include<stdio.h>
#include<iostream>
#include<string.h>
using namespace std;
const int maxn = 2e5 + 10;
typedef long long LL;
const int M = 16777216;
long long c[maxn], a[maxn], l_min[maxn], r_max[maxn];
int lowbit(int x)
{
return -x&x;
}
void update(int pos, long long val)
{
for(int i = pos; i < maxn; i += lowbit(i))
{
c[i] += val;
}
}
LL query(int pos)
{
long long res = 0;
for(int i = pos; i > 0; i -= lowbit(i))
{
res = (res+c[i])%M;
}
return res%M;
}
int main()
{
int n;
ios::sync_with_stdio(false);
cin >> n;
for(int i = 1; i <= n; i++)
{
cin >> a[i];
}
memset(c, 0, sizeof(c));
memset(l_min, 0, sizeof(l_min));
memset(r_max, 0, sizeof(r_max));
for(int i = 1; i <= n; i++)
{
l_min[i] = query(a[i]-1);
update(a[i], 1);
}
memset(c, 0, sizeof(c));
for(int i = n; i >= 1; i--)
{
r_max[i] = query(n)-query(a[i]);
update(a[i], 1);
}
LL abxx = 0;
for(int i = 1; i <= n; i++)
{
abxx = (abxx+l_min[i]*(r_max[i]*(r_max[i]-1)/2))%M;
}
LL abcd = 0;
memset(c, 0, sizeof(c));
for(int i = 1; i <= n; i++)
{
abcd = (abcd+(query(a[i]-1)*r_max[i])%M)%M;
update(a[i], l_min[i]);
}
LL ans = (abxx-abcd+M)%M;
cout << ans << endl;
return 0;
}