题目描述
撷来一缕清风飘渺
方知今日书信未到
窗外三月天霁垂柳新长枝条
风中鸟啼犹带欢笑
——《清风醉梦》
小奇望着青天中的悠悠白云,开始了无限的遐想,在它的视野中,恰好有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
提示
对于10%的数据n<=600;对于40%的数据n<=5000;
对于100%的数据n<=200000。
题意:就是求一个四元组构成 a < b < d < c (对于在序列中的下表要求 a < b < c < d)
思想 :
先求出来12xx这种形式的四元组 减去 1234 这样的四元组就是要求的 1243这样的四元组
12xx的求解方式就是枚举第2个点 比他小的个数 * 比他大的个数里面的选2个 l[i]表示比a[i]小的个数 r[i] = a[i] - l[i] - 1 表示后边有多少比他小的个数
故可以表示为 l[i] * (n- i - r[i] )*(a[i] - i - 1 - r[i]) / 2 n - i 代表有他后边有多少数 再减去比他小的个数 就是比他大的个数
1234的求解方式是枚举第三个数 从它右边选择一个数 就是 (n- i -r[i])
然后从左边选择一个12形式的数 选择12的个数 等于第i个点前边构成 a<b这样的和
比如 1 2 3 4 查询3的时候就等于 1 查询4就等于3 因为 等前边有比自己小的才会对后边有贡献,所以2的时候贡献为1, 只能构成12这样的 对于4的时候不但有1 2 这样的 还有 1 3 2 3 就是以i结尾前边有多少比他小的 不就是构成多少了吗
所以就add(a[i],l[i]) 然后用sum- sum1取模就行了。
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
int n;
ll a[200005];
ll l[200005];
ll r[200005];
ll sum[200005];
ll Sum[200005];
const ll mod=16777216;
void add(int x,ll valu)
{
while(x<=n)
{
sum[x]+=valu;
x=x+(x&(-x));
}
}
void Add(int x,int valu)
{
while(x<=n)
{
Sum[x]+=valu;
x=x+(x&(-x));
}
}
ll query(int x)
{
ll ans=0;
while(x>0)
{
ans+=sum[x];
x=x-(x&(-x));
}
return ans;
}
ll Query(int x)
{
ll ans=0;
while(x>0)
{
ans+=Sum[x];
x=x-(x&(-x));
}
return ans;
}
int main()
{
scanf("%d",&n);
for(int i = 1;i <= n;i++)
scanf("%lld",&a[i]);
for(int i = 1;i <= n;i++)
{
l[i] = query(a[i]);//前边有多少比他小的
r[i] = a[i] - l[i] -1 ;//后边有多少比他小的
add(a[i],1);
}
ll sum = 0 ,sum1 = 0;
for(int i=1;i<=n;i++)//求出来 12xx这样的方案数
sum = (sum+l[i]*((n-i-r[i])*(n-i-r[i]-1)/2))%mod;
for(int i=1;i<=n;i++)//求出来1234的方案数
{
sum1 = (sum1+(Query(a[i])*(n-i-r[i]))%mod)%mod;
Add(a[i],l[i]);
}
printf("%lld\n",(sum-sum1+mod)%mod);
return 0;
}