问题 M: 小奇遐想
时间限制: 1 Sec 内存限制: 128 MB
提交: 421 解决: 106
[提交] [状态] [讨论版] [命题人:admin]
题目描述
撷来一缕清风飘渺
方知今日书信未到
窗外三月天霁垂柳新长枝条
风中鸟啼犹带欢笑
——《清风醉梦》
小奇望着青天中的悠悠白云,开始了无限的遐想,在它的视野中,恰好有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。
题解:询问1243的种类数,问题可以转换成12xx-1234,预处理每个位置的数字左边比它小的数字的个数L[i]和右边比它大的数字的个数R[i],那么12xx就可以枚举每个位置然后L[i]*C(2,R[i]),求和即可。1234则枚举3的位置让树状数组处理12的个数*r[i]求和即可。
其中树状数组预处理左边比它小的个数,访问到每个数字的时候在a[i]处add(1)即可,然后每次query(a[i])就是左边比它小的数字的个数。对于1234来说就直接对于每个位置add(a[i],l[i]),每个数字将左边的1的个数用树状数组维护
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=16777216;
const int maxn=1e6+7;
ll a[maxn],n;
ll tree[maxn],lmin[maxn],rmin[maxn];
void add(int x,ll val)
{
for(int i=x;i<=n;i+=i&-i)
tree[i]+=val;
}
ll query(int x)
{
ll ans=0;
for(int i=x;i;i-=i&-i)
ans+=tree[i];
return ans;
}
void make_wen()
{
for(int i=1;i<=n;i++)
{
lmin[i]=query(a[i]);
rmin[i]=a[i]-lmin[i]-1;
add(a[i],1);
}
ll tot=0;
for(int i=1;i<=n;i++)
tot=(tot+lmin[i]*(n-i-rmin[i])*(n-i-rmin[i]-1)/2)%mod;
memset(tree,0,sizeof(tree));
ll res=0;
for(int i=1;i<=n;i++)
{
res=(res+query(a[i])*(n-i-rmin[i])%mod)%mod;
add(a[i],lmin[i]);
}
printf("%lld\n",(tot-res+mod)%mod);
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
scanf("%lld",&a[i]);
make_wen();
}