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;
}
此生无悔入OI 来生AK IOI

浙公网安备 33010602011771号