描述
题解
向大牛致敬——xdlove,思量许久,不能参透,大牛题解一语惊醒梦中人~~~
首先可以明确一点,一个最小的严格递增的正整数子序列为1,2,3,……….n,那么对于题目给出的任何一个序列,需要最少改变多少个使得序列变为严格递增的子序列呢? 对于每一个数a[i],把a[i] 变为 a[i] - i,如果此时a[i]小于0,说明他连最小的严格递增子序列都不符合,那么它一定要修改,再处理完这些小于0的数后,剩下的数又应该怎么操作呢? 直接求出最长的非严格递增子序列就行了. 具体为什么,和其它的数经过这样操作都能够换成合法的数,只能自己意会下哒!(大牛题解)
代码
#include <iostream>
#include <cstdio>
using namespace std;
const int MAXN = 1e5 + 10;
int A[MAXN];
/*
* 递增/递减/非递增/非递减
*/
int f[MAXN];
int d[MAXN]; // d[i]用于记录a[0...i]的最大长度
int bsearch(const int *f, int size, const int &a)
{
int l = 0, r = size - 1;
while (l <= r)
{
int mid = (l + r) / 2;
if (a >= f[mid - 1] && a < f[mid])
{
return mid;
}
else if (a < f[mid])
{
r = mid - 1;
}
else
{
l = mid + 1;
}
}
return -1;
}
int LIS(const int *a, const int &n)
{
int i, j, size = 1;
f[0] = a[0];
d[0] = 1;
for (i = 1; i < n; ++i)
{
if (a[i] < f[0])
{
j = 0;
}
else if (a[i] >= f[size - 1])
{
j = size++;
}
else
{
j = bsearch(f, size, a[i]);
}
f[j] = a[i];
d[i] = j + 1;
}
return size;
}
int main(int argc, const char * argv[])
{
freopen("/Users/zyj/Desktop/input.txt", "r", stdin);
int N;
cin >> N;
int a;
int pos = 0;
for (int i = 1; i <= N; i++)
{
scanf("%d", &a);
a -= i;
if (a >= 0)
{
A[pos++] = a;
}
}
if (pos == 0)
{
cout << N << '\n';
}
else
{
cout << N - LIS(A, pos) << '\n';
}
return 0;
}