【bzoj5157】[Tjoi2014]上升子序列 树状数组

题目描述

求一个数列本质不同的至少含有两个元素的上升子序列数目模10^9+7的结果。


题解

树状数组

傻逼题,离散化后直接使用树状数组统计即可。由于要求本质不同,因此一个数要减去它前一次出现时的贡献(即以它上一次出现的位置为最后一个元素的上升子序列数目)统计到答案中。

由于要包含至少两个元素,因此还需要减掉不同数的数目。

时间复杂度 $O(n\log n)$ 

#include <cstdio>
#include <algorithm>
#define N 100010
#define mod 1000000007
using namespace std;
int n , a[N] , v[N] , pos[N] , last[N] , val[N] , f[N];
inline void add(int x , int a)
{
    int i;
    for(i = x ; i <= n ; i += i & -i)
        f[i] = (f[i] + a) % mod;
}
inline int query(int x)
{
    int i , ans = 0;
    for(i = x ; i ; i -= i & -i)
        ans = (ans + f[i]) % mod;
    return ans;
}
int main()
{
    int i , sum = 0;
    scanf("%d" , &n);
    for(i = 1 ; i <= n ; i ++ ) scanf("%d" , &a[i]) , v[i] = a[i];
    sort(v + 1 , v + n + 1);
    for(i = 1 ; i <= n ; i ++ )
    {
        a[i] = lower_bound(v + 1 , v + n + 1 , a[i]) - v;
        if(!pos[a[i]]) sum ++ ;
        last[i] = pos[a[i]] , pos[a[i]] = i;
    }
    for(i = 1 ; i <= n ; i ++ ) val[i] = query(a[i] - 1) + 1 , add(a[i] , (val[i] - val[last[i]] + mod) % mod);
    printf("%d\n" , (query(n) - sum + mod) % mod);
    return 0;
}

 

posted @ 2018-02-23 13:28  GXZlegend  阅读(545)  评论(0编辑  收藏  举报