首页 > 代码库 > BZOJ1109 [POI2007]堆积木Klo

BZOJ1109 [POI2007]堆积木Klo

第一眼看出是动态规划。

然后写方程:令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 }
View Code


 

BZOJ1109 [POI2007]堆积木Klo