1376 最長遞增子序列的數量(dp+線段樹優化)

       數組A包含N個整數(可能包含相同的值)。設S爲A的子序列且S中的元素是遞增的,則S爲A的遞增子序列。如果S的長度是所有遞增子序列中最長的,則稱S爲A的最長遞增子序列(LIS)。A的LIS可能有很多個。例如A爲:{1 3 2 0 4},1 3 4,1 2 4均爲A的LIS。給出數組A,求A的LIS有多少個。由於數量很大,輸出Mod 1000000007的結果即可。相同的數字在不同的位置,算作不同的,例如 {1 1 2} 答案爲2。


題解:離線。線段樹維護區間最長上升序列的長度和個數。


#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define lc idx<<1
#define rc idx<<1|1
#define lson l,mid,lc
#define rson mid+1,r,rc
#define mod 1000000007

using namespace std;

typedef long long ll;

const int N=50005;

int n;
int dp[N],dn[N];

struct node
{
    int v;
    int id;
    bool operator < (const node &b)const
    {
        if(v==b.v)
            return id>b.id;
        return v<b.v;
    }
} a[N];

struct tree
{
    int Max,num;
    tree() {};
    tree(int ma,int nu)
    {
        Max=ma;
        num=nu;
    }
} T[N<<2];

void push_up(int idx)
{
    T[idx].Max=max(T[lc].Max,T[rc].Max);
    if(T[lc].Max==T[rc].Max)
    {
        T[idx].num=(T[lc].num+T[rc].num)%mod;
    }
    else
    {
        T[idx].num=T[lc].Max>T[rc].Max?T[lc].num:T[rc].num;
    }
}

void build(int l,int r,int idx)
{
    if(l==r)
    {
        T[idx].Max=0;
        T[idx].num=0;
        return;
    }
    int mid=(l+r)>>1;
    build(lson);
    build(rson);
    push_up(idx);
}

void update(int l,int r,int idx,int x,tree y)
{
    if(l==r)
    {
        T[idx]=tree {y.Max,y.num};
        return;
    }
    int mid=(l+r)>>1;
    if(x<=mid)
    {
        update(lson,x,y);
    }
    else
    {
        update(rson,x,y);
    }
    push_up(idx);
}
tree query(int l,int r,int idx,int x,int y)
{
    if(x<=l&&r<=y)
    {
        return T[idx];
    }
    int mid=(l+r)>>1;
    tree res=tree {0,0};
    if(x<=mid)
    {
        res=query(lson,x,y);
    }
    if(y>mid)
    {
        tree t=query(rson,x,y);
        if(t.Max==res.Max){
                res.num+=t.num;
                res.num%=mod;
        }
        else if(t.Max>res.Max)
        {
            res=tree {t.Max,t.num};
        }
    }
    return res;
}

int main()
{
    freopen("test.in","r",stdin);
    while(cin>>n)
    {
        for(int i=1; i<=n; i++)
        {
            scanf("%d",&a[i].v);
            a[i].id=i;
        }
        sort(a+1,a+n+1);
        build(1,n,1);
        for(int i=1; i<=n; i++)
        {
            tree t=query(1,n,1,1,a[i].id);
            if(t.Max==0)t.num=1;//前面沒有數
            t.Max++;
            update(1,n,1,a[i].id,t);
        }
        cout<<T[1].num<<endl;
    }
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章