第一眼看出是动态规划。
然后写方程:令f[i]表示下面i个积木里面必须取第i个的情况下满足要求的最多个数。
则f[i] = max(f[j] + 1)
其中j满足以下三个条件
(1) j < i
(2) a[j] < a[i]
(3) a[i] - a[j] <= i - j
把(3)变形:a[i] - i <= a[j] - j ......(4)
这时ZYH神犇告诉我(2) + (3)可以推出(1),即只需满足(2)、(4)两个条件即可
于是得到方法了:先排序(第一关键字a[i] - i升序,第二关键字a[i]降序),然后直接求新数列的LIS即可。
其实这里求LIS时,每次要求[1, i]的最大值,不需要线段树维护,只要树状数组就可以了。
1 /************************************************************** 2 Problem: 1109 3 User: rausen 4 Language: C++ 5 Result: Accepted 6 Time:332 ms 7 Memory:3148 kb 8 ****************************************************************/ 9 10 #include <cstdio> 11 #include <cmath> 12 #include <algorithm> 13 14 using namespace std; 15 16 struct Rec{ 17 int num, x; 18 } a[150000]; 19 int ans, n, f[150000], Bit[150000]; 20 21 bool cmp(Rec a, Rec b){ 22 return a.x == b.x ? a.num < b.num : a.x > b.x; 23 } 24 25 inline int lowbit(int x){ 26 return x & (-x); 27 } 28 29 int query(int x){ 30 if (!x) return 0; 31 int res = 0; 32 while (x){ 33 res = max(res, Bit[x]); 34 x -= lowbit(x); 35 } 36 return res; 37 } 38 39 void add(int x, int y){ 40 while (x <= n){ 41 Bit[x] = max(Bit[x], y); 42 x += lowbit(x); 43 } 44 } 45 46 int main(){ 47 scanf("%d", &n); 48 for (int i = 1; i <= n; ++i){ 49 scanf("%d", &a[i].num); 50 a[i].x = a[i].num - i; 51 } 52 sort(a + 1, a + n + 1, cmp); 53 54 for (int i = 1; i <= n; ++i){ 55 if (a[i].x > 0) continue; 56 int X = query(a[i].num - 1); 57 f[i] = X + 1; 58 ans = max(ans, f[i]); 59 add(a[i].num, f[i]); 60 } 61 printf("%d\n", ans); 62 return 0; 63 }
By Xs酱~ 转载请说明
博客地址:http://www.cnblogs.com/rausen