您的位置:首页 > 其它

BZOJ1109 [POI2007]堆积木Klo

2014-09-30 11:20 190 查看
第一眼看出是动态规划。

然后写方程:令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]的最大值,不需要线段树维护,只要树状数组就可以了。

/**************************************************************
Problem: 1109
User: rausen
Language: C++
Result: Accepted
Time:332 ms
Memory:3148 kb
****************************************************************/

#include <cstdio>
#include <cmath>
#include <algorithm>

using namespace std;

struct Rec{
int num, x;
} a[150000];
int ans, n, f[150000], Bit[150000];

bool cmp(Rec a, Rec b){
return a.x == b.x ? a.num < b.num : a.x > b.x;
}

inline int lowbit(int x){
return x & (-x);
}

int query(int x){
if (!x) return 0;
int res = 0;
while (x){
res = max(res, Bit[x]);
x -= lowbit(x);
}
return res;
}

void add(int x, int y){
while (x <= n){
Bit[x] = max(Bit[x], y);
x += lowbit(x);
}
}

int main(){
scanf("%d", &n);
for (int i = 1; i <= n; ++i){
scanf("%d", &a[i].num);
a[i].x = a[i].num - i;
}
sort(a + 1, a + n + 1, cmp);

for (int i = 1; i <= n; ++i){
if (a[i].x > 0) continue;
int X = query(a[i].num - 1);
f[i] = X + 1;
ans = max(ans, f[i]);
add(a[i].num, f[i]);
}
printf("%d\n", ans);
return 0;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: