洛谷 P1637 三元上升子序列(树状数组)

来源:互联网 发布:增值税开票软件安装 编辑:程序博客网 时间:2024/06/05 19:18

传送门
日常来水一篇(滑稽)
这题本来觉得像逆序对那样插入,查询,然后ans+=num*(num-1),然后两个样例都没过,才发现这么是错的,因为这样前两个的顺序就无法保证了。
然后就想正解。
然后就想到一个类似dp的做法:

f(i,j)ij
然后就可以这样dp:
f(i,j)=i1k=1[ak<ai]f(k,j1)

发现可以用树状数组优化
因为dp的过程实际就是查找所有小于它的数的长度减一的上升子序列数量
然后就可以离散化之后插入,查询
时间复杂度:O(nlogn)

代码:

#include<cstdio>#include<cstring>#include<iostream>#include<cmath>#include<algorithm>#include<cstdlib>#define ll long longusing 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;}
原创粉丝点击