P1637

三元上升子序列

题目描述

Erwin 最近对一种叫 thair 的东西巨感兴趣。。。

在含有 \(n\) 个整数的序列 \(a_1,a_2,\ldots,a_n\) 中,三个数被称作thair当且仅当 \(i<j<k\)\(a_i<a_j<a_k\)

求一个序列中 thair 的个数。

输入格式

开始一行一个正整数 \(n\),

以后一行 \(n\) 个整数 \(a_1,a_2,\ldots,a_n\)

输出格式

一行一个整数表示 thair 的个数。

样例 #1

样例输入 #1

4
2 1 3 4

样例输出 #1

2

样例 #2

样例输入 #2

5
1 2 2 3 4

样例输出 #2

7

提示

样例2 解释

\(7\)thair 分别是:

  • 1 2 3
  • 1 2 4
  • 1 2 3
  • 1 2 4
  • 1 3 4
  • 2 3 4
  • 2 3 4

数据规模与约定

  • 对于 \(30\%\) 的数据 保证 \(n\le100\)
  • 对于 \(60\%\) 的数据 保证 \(n\le2000\)
  • 对于 \(100\%\) 的数据 保证 \(1 \leq n\le3\times10^4\)\(0\le a_i\leq 10^5\)

好题!!!
开始的思路是枚举i,j 再logn优化k
但是 可以枚举j啊!!! 枚举j了算两边都可以用BIT啊啊啊!!!
solution:
	枚举中间的j
	由乘法原理 只用算j左边比a[j]小的个数l[j]*j右边比a[j]大的个数r[j]
这就是树状数组的标准用法!
先离散化 再分别求l[i] r[i]
仿照树状数组求逆序对的方法可以o(logn)处理
总时间复杂度o(n*logn*logn)足以通过本题
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,b[30005],a[30005],c[30005],tr1[30005*4],tr2[30005*4],tot,l[30005],r[30005];
int lowbit(int x){return x&(-x);}
void add(int *tr,int p,int x)
{
	for(;p<=n;p+=lowbit(p))
	{
		tr[p]+=x;
	}
}
int query(int *tr,int p)
{
	int ans=0;
	for(;p;p-=lowbit(p))
	{
		ans+=tr[p];
	}
	return ans;
}
signed main()
{
	ios::sync_with_stdio(false);
	cin>>n;
	for(int i=1;i<=n;i++)cin>>b[i],c[i]=b[i];
	sort(b+1,b+n+1);
	for(int i=1;i<=n;i++)
	{
		int pos=lower_bound(b+1,b+n+1,c[i])-b;
		a[i]=pos;
	}
//	for(int i=1;i<=n;i++)cout<<a[i]<<" ";
	for(int i=1;i<=n;i++)
	{
		add(tr1,a[i],1);
		l[i]=query(tr1,a[i]-1);
	}
	for(int i=n;i>=1;i--)
	{
		add(tr2,a[i],1);
		r[i]=(n-i+1)-query(tr2,a[i]);
	}
	for(int i=2;i<=n-1;i++)tot+=l[i]*r[i];
	cout<<tot<<"\n";
	return 0;
} 
posted @ 2023-01-04 22:03  PKU_IMCOMING  阅读(3)  评论(0)    收藏  举报