就是找不降低子序列的個數。ios
一開始想着先離散化,而後再作個 $dp$,發現用 $dp$ 的話時間複雜度是 $\text{O}(n^2)$ 的,穩穩超時。數組
這裏說說 $dp$:spa
設 $dp[i]$ 表示以 $a[i]$ 爲結尾的不降低子序列的個數。code
那麼狀態轉移方程就顯而易見了:blog
$$dp[i] = sum(dp[j])+1,a[j]<=a[i]\&\&j<i$$string
遂放棄 $dp$,轉向另外一種思路:樹狀數組。it
由於要求逆序列的個數。因此選擇用樹狀數組來作,思路以下:io
將數據離散化後,按照原來輸入的順序從小到大將每個數的影響加到樹狀數組中。那麼影響是啥?class
就是會對當前這個數後面的比它大的數字形成影響,由於會構成逆序列。而後你就牛逼了。。。stream
這樣的話,每次詢問一個數時,只有它前面的數的影響才被加了進去。就能夠保證詢問的正確性。
#include <algorithm> #include <iostream> #include <cstring> #include <cstdio> using namespace std; const int maxn = 1e5+3, HA = 1e9+7; int n, s[maxn], a[maxn], tmp[maxn], bit[maxn], NI[maxn]; inline int lowbit(int x) {return x & -x;} inline void add(int pos, int num) { while (pos <= n) { bit[pos] = ((num % HA) + (bit[pos] % HA)) % HA; pos += lowbit(pos); } } inline int query(int pos) { int res = 0; while (pos >= 1) { res = ((bit[pos] % HA) + (res % HA)) % HA; pos -= lowbit(pos); } return res; } int main() { while (~scanf("%d", &n)) { memset(NI, 0, sizeof(NI)); memset(bit, 0, sizeof(bit)); for(int i=1; i<=n; i++) { scanf("%d", &s[i]); tmp[i] = s[i]; } sort(tmp+1, tmp+1+n); for(int i=1; i<=n; i++) a[i] = lower_bound(tmp+1, tmp+1+n, s[i])-tmp; for(int i=1; i<=n; i++) { NI[i] = query(a[i]); NI[i] %= HA; add(a[i], NI[i] + 1); } printf("%d\n", query(n)); } }