传送门
日常来水一篇(滑稽)
这题本来觉得像逆序对那样插入,查询,然后ans+=num*(num-1),然后两个样例都没过,才发现这么是错的,因为这样前两个的顺序就无法保证了。
然后就想正解。
然后就想到一个类似dp的做法:
f(i,j)代表以第i个数结尾的长度为j的上升子序列数量
然后就可以这样dp:
f(i,j)=∑i−1k=1[ak<ai]∗f(k,j−1)
然后这就是 O(n2)
发现可以用树状数组优化
因为dp的过程实际就是查找所有小于它的数的长度减一的上升子序列数量
然后就可以离散化之后插入,查询
时间复杂度: O(nlogn)
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstdlib>
#define ll long long
using namespace std;
inline int read(){
int x=0;char ch=' ';int f=1;
while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
if(ch=='-')f=-1,ch=getchar();
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*f;
}
int n,size;
ll a[30001];
ll b[30001];
int t[30001];
inline int lowbit(int x){
return x&-x;
}
inline void update(int x){
while(x<=size){
t[x]++;
x+=lowbit(x);
}
}
inline int query(int x){
int ans=0;
while(x){
ans+=t[x];
x-=lowbit(x);
}
return ans;
}
ll t2[30001];
inline void update2(int x,int v){
while(x<=size){
t2[x]+=v;
x+=lowbit(x);
}
}
inline int query2(int x){
int ans=0;
while(x){
ans+=t2[x];
x-=lowbit(x);
}
return ans;
}
inline int Hash(ll x){
return lower_bound(b+1,b+size+1,x)-b;
}
int main(){
n=read();
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
b[i]=a[i];
}
sort(b+1,b+n+1);
size=unique(b+1,b+n+1)-b-1;
ll ans=0;
for(int i=1;i<=n;i++){
int rk=Hash(a[i]);
update(rk);
int num=query(rk-1);
update2(rk,num);
ans+=query2(rk-1);
}
printf("%lld",ans);
return 0;
}