BZOJ 1109: [POI2007]堆积木Klo

Description

  Mary在她的生日礼物中有一些积木。那些积木都是相同大小的立方体。每个积木上面都有一个数。Mary用他的
所有积木垒了一个高塔。妈妈告诉Mary游戏的目的是建一个塔,使得最多的积木在正确的位置。一个上面写有数i
的积木的正确位置是这个塔从下往上数第i个位置。Mary决定从现有的高塔中移走一些,使得有最多的积木在正确
的位置。请你告诉Mary她应该移走哪些积木。

Input

  第一行为一个数n,表示高塔的初始高度。第二行包含n个数a1,a2,…,an,表示从下到上每个积木上面的数。
(1<=n<=100000,1<=ai<=1000000)。

Output

  注意:请输出最多有多少点可以处在正确位置

Sample Input

5

1 1 2 5 4

Sample Output

3

分析

我们设 f[i] 表示前 i 位能到达自己位置的数最多有多少,难么我们就可以得到一个dp方程:

f[i]=max(f[j]+1)(j<ia[j]<a[i]a[i]a[j]ij)

我们观察一下三个限制条件
1. j<i
2. a[j]<a[i]
3. a[i]a[j]ij ja[j]ia[i]
我们按照 ia[i] 作为第一关键字 a[i] 作为第二关键字,做一遍最长上升子序列即可

代码

#include <bits/stdc++.h>

#define N 1000100

using namespace std;

int read()
{
    int x = 0, f = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9') {if (ch == '-') f = -1; ch = getchar();}
    while (ch >= '0' && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();}
    return x * f;
}

struct NOTE
{
    int x,y;

    friend bool operator < (NOTE a,NOTE b)
    {
        if (a.x == b.x)
            return a.y < b.y;
        return a.x < b.x;
    }
}num[N];

int tot;

int p[N];

int main()
{
    int n = read();
    for (int i = 1; i <= n; i++)
    {
        int x = read();
        if (x > i)
            continue;
        num[++tot].x = i - x;
        num[tot].y = x;
    }

    std::sort(num + 1, num + tot + 1);

    memset(p,127,sizeof(p));
    int ans = 0;
    for (int i = 1; i <= tot; i++)
    {
        int l = 1, r = ans, mn = 0;
        while (l <= r)
        {
            int mid = (l + r) >> 1;
            if (num[i].y > p[mid])
                mn = mid, l = mid + 1;
            else r = mid - 1;
        }
        ans = std::max(ans, mn + 1);
        p[mn + 1] = std::min(p[mn + 1], num[i].y);
    }
    printf("%d\n",ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值