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方程:
我们观察一下三个限制条件
1. j<i
2. a[j]<a[i]
3. a[i]−a[j]≤i−j 即 j−a[j]≤i−a[i]
我们按照 i−a[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);
}