小奇遐想(树状数组)

小奇遐想

时间限制: 1 Sec  内存限制: 128 MB

题目描述

撷来一缕清风飘渺
方知今日书信未到
窗外三月天霁垂柳新长枝条
风中鸟啼犹带欢笑
——《清风醉梦》
小奇望着青天中的悠悠白云,开始了无限的遐想,在它的视野中,恰好有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<c<d与a<b<d<c的情况,再减去a<b<c<d时的情况,根据树状数组统计比变量b小的大的数。

#include<bits/stdc++.h>

typedef long long LL;
using namespace std;

const long long mod = 16777216;
LL a[200005], c1[200005], c2[200005], l[200005], r[200005];
int n;

int lowbit(int x){
	return x & (-x);
}

void add1(int x){
	while(x <= n){
		c1[x]++;
		x += lowbit(x);
	}
}

void add2(int x, int num){
	while(x <= n){
		c2[x] += num;
		x += lowbit(x);
	}
}

int sum1(int x){
	int res = 0;
	while(x){
		res += c1[x];
		x -= lowbit(x);
	}
	return res;
}

int sum2(int x){
	int res = 0;
	while(x){
		res += c2[x];
		x -= lowbit(x);
	}
	return res;
}

int main()
{
	scanf("%d", &n);
	for (int i = 1; i <= n; i++) scanf("%lld", &a[i]);
	LL ans1 = 0, ans2 = 0;
	for (int i = 1; i <= n; i++){
		l[i] = sum1(a[i]);//左边有多少比当前小的,就有多少种选法(选完a,b)
		r[i] = n - i - (a[i] - l[i] - 1);//(选c,d)n-i表示后边最多有(n-i)中选法,减去比a[i]小的数(当前位置后边可能有比a[i]小的数,保证c,d大于a,b)
		add1(a[i]);//更新
	}
	for (int i = 1; i <= n; i++){
		ans1 = (ans1 + l[i] * (r[i] * (r[i] - 1) / 2) % mod) % mod;//(a,b)选法有l[i]种,(c,d)选法为C(r[i],2)(这里没考虑c>b,后边再减)
	}
	//cout << ans1 << endl;
	for (int i = 1; i <= n; i++){
		ans2 = (ans2 + sum2(a[i]) * r[i] % mod) % mod;
		//统计当d大于c时的数时的个数
		add2(a[i], l[i]);//更新选(a选比a[i]小的数,b=a[i])时有多少种
	}
	printf("%lld\n", ((ans1 - ans2) % mod + mod) % mod);

	return 0;
}

猜你喜欢

转载自blog.csdn.net/oneplus123/article/details/84961909