Upc5727 : 小奇遐想 (树状数组)

题目描述

撷来一缕清风飘渺
方知今日书信未到
窗外三月天霁垂柳新长枝条
风中鸟啼犹带欢笑
——《清风醉梦》
小奇望着青天中的悠悠白云,开始了无限的遐想,在它的视野中,恰好有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)

扫描二维码关注公众号,回复: 2550849 查看本文章

思想 :

先求出来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;
} 

猜你喜欢

转载自blog.csdn.net/passer__/article/details/81266487