题目链接:http://exam.upc.edu.cn/problem.php?cid=1390&pid=12
题目描述:
撷来一缕清风飘渺
方知今日书信未到
窗外三月天霁垂柳新长枝条
风中鸟啼犹带欢笑
——《清风醉梦》
小奇望着青天中的悠悠白云,开始了无限的遐想,在它的视野中,恰好有n朵高度不同的白云排成一排,他想从左到右选出四朵白云a,b,c,d,使得h_a<h_b<h_d<h_c,即看起来像是彩虹的形状!它想知道有多少种方案数。
输入
第一行包括1个整数n。
第二行包括n个整数,第i个正数表示h_i,保证这n个整数是n的一个全排列。
分析:
对于给出的一列数:可以先求出排序为 1 2 X X 的个数sum1,要保证:XX都要比第2个数大,且第1 个数,和第2 个数是递增的
然后求出排序为1 2 3 4 的个数sum2,其中 第1 ,2 ,3, 4个数都必须保证其为严格递增的。
使用树状数组求逆序数即可。
然后sum1-sum2 即是所要求的 排序为1 2 4 3 的个数。
#include<stdio.h>
#include<string.h>
#define ll long long int
#define mode 16777216
ll a[200010],u[200010],v[200010];
ll maze[200010],ans[200010],n;
ll lowbit(ll x)
{
return x&(-x);
}
void add(ll x,ll num)
{
while(x<=n){
maze[x]+=num;
x+=lowbit(x);
}
}
ll summ(ll x)
{
ll sum=0;
while(x){
sum+=maze[x];
x-=lowbit(x);
}
return sum;
}
void panadd(ll x,ll num)
{
while(x<=n){
ans[x]+=num;
x+=lowbit(x);
}
}
ll pansumm(ll x)
{
ll sum=0;
while(x){
sum+=ans[x];
x-=lowbit(x);
}
return sum;
}
int main()
{
int i;
ll sum1,sum2;
scanf("%lld",&n);
for(i=1;i<=n;i++)
scanf("%lld",&a[i]);
for(i = 1;i <= n;i++){
u[i]=summ(a[i]);
v[i]=a[i]-u[i]-1;
add(a[i],1);
}
sum1=0;
for(i=1;i<=n;i++)
sum1= (sum1+u[i]*((n-i-v[i])*(n-i-v[i]-1)/2))%mode;//组合数,从大的数中任意选两个cn2
sum2 =0;
for(i=1;i<=n;i++){
sum2 = (sum2+(pansumm(a[i])*(n-i-v[i]))%mode)%mode;
panadd(a[i],u[i]); // pansumm(a[i])表示a[i]的三个递增排序的个数
}
ll k=(sum1-sum2+mode)%mode;
printf("%lld\n",k);
return 0;
}