很容易可以想到状态转移方程:
dp[i] = segma: dp[j] ( j < i && a[j] <= a[i] ), 其中dp[i]表示以a[i]结尾的不降子序列的个数。
但是n非常大,n^2的算法必然TLE,仔细想想其实式子右边是一个区间和的形式,即小于等于a[i]的a[j]的dp[j]的和,所以可以将a[i]离散化成t后将dp[i]的值存在t位置上,每次求解dp[i]就是查询一个前缀和,可以用树状数组来维护。
举个例子:对于1,50,13,34这四个数,离散化后变成了1,4,2,3。显然dp[1] = 1,所以我们在1位置插入1;而dp[2]就等于查询位置1到4(1+0+0+0)的和再加1,所以dp[2] = 2,我们在4位置插入2;dp[3]就等于(1+0)再加1,dp[3] = 2,我们在2位置插入2;dp[4]就等于(1+2+0)再加1为4,在位置3插入4,最后答案为整个数列的和:1+2+4+2=9.
1 #include <algorithm> 2 #include <iostream> 3 #include <cstring> 4 #include <cstdio> 5 using namespace std; 6 7 typedef long long ll; 8 const int N = 100001; 9 const int MOD = 1000000007; 10 int c[N]; 11 12 struct Node 13 { 14 ll s; 15 int id; 16 } node[N]; 17 18 int lb( int i ) 19 { 20 return i & -i; 21 } 22 23 void set( int i, int x ) 24 { 25 while ( i < N ) 26 { 27 c[i] += x; 28 c[i] %= MOD; 29 i += lb(i); 30 } 31 } 32 33 int get( int i ) 34 { 35 int ans = 0; 36 while ( i > 0 ) 37 { 38 ans += c[i]; 39 ans %= MOD; 40 i -= lb(i); 41 } 42 return ans; 43 } 44 45 bool cmp1( Node n1, Node n2 ) 46 { 47 if ( n1.s != n2.s ) return n1.s < n2.s; 48 return n1.id < n2.id; 49 } 50 51 bool cmp2( Node n1, Node n2 ) 52 { 53 return n1.id < n2.id; 54 } 55 56 int main () 57 { 58 int n; 59 while ( scanf("%d", &n) != EOF ) 60 { 61 for ( int i = 1; i <= n; i++ ) 62 { 63 scanf("%I64d", &node[i].s); 64 node[i].id = i; 65 } 66 sort( node + 1, node + 1 + n, cmp1 ); 67 for ( int i = 1; i <= n; i++ ) 68 { 69 node[i].s = i; 70 } 71 sort( node + 1, node + 1 + n, cmp2 ); 72 memset( c, 0, sizeof(c) ); 73 for ( int i = 1; i <= n; i++ ) 74 { 75 int pn = node[i].s; 76 int nn = get(pn) + 1; 77 set( pn, nn ); 78 } 79 printf("%d\n", get(n)); 80 } 81 return 0; 82 }
时间: 2024-10-07 11:15:34