【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; }