题意:
1294 修改数组
给出一个整数数组A,你可以将任何一个数修改为任意一个正整数,最终使得整个数组是严格递增的且均为正整数。问最少需要修改几个数?
输入
第1行:一个数N表示序列的长度(1 <= N <= 100000)。
第2 - N + 1行:每行1个数,对应数组元素。(0 <= A[i] <= 10^9)
输出
输出最少需要修改几个数使得整个数组是严格递增的。
输入样例
5
1
2
2
3
4
输出样例
3
思路:
(1) 题目要求是严格递增的qaq。。首先考虑第一种i > a[i] 。。这种肯定是要改的,为什么呢?我们题目要求的是正整数所以a[i]最小就是i了 --> 对于a[i] < i这种情况必须要改
if(a[i] - i >= 0)
b[++cnt] = a[i] - i;
else cur++;//一定需要改动的部分。。
(2)对于剩下的可能要改,可能不改的数,先把他们存到一个新的数组里面。到底怎么判断改还是不改呢???
它们在原数组里一定要满足对于i < j , a[j] - a[i] >= j - i,就有a[j] - j >= a[i] - i。。所以对于每一个不满足条件1的a[i],把a[i] - i存到一个新的数组里,找b[i]的不严格递增的最长子序列的长度,这个就是不需要改动的数目。。。
(3)n - 不需要改动的数目 = ans
注意:我们知道求最长上升子序列可以dp,但是数据范围比较大。。会T掉。。。求不严格递增的子序列的数目我们也可以二分求解
二分代码如下:
int l = 1;
int r = now;
int ans;
while(l <= r){
int mid = (l + r) / 2;
if(a[mid] > b[i]){
r = mid - 1;
ans = mid;
}
else{
l = mid + 1;
}
}
a[ans] = b[i];
代码实现:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<string>
#include<queue>
#include<stack>
#include<map>
#include<vector>
#include<set>
#include<cstdlib>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 5;
const int inf = 1e9 + 5;
int b[maxn];
int cnt = 0;
int lis(){
}
int main(){
int n;
int a[maxn];
scanf("%d",&n);
int cur = 0;
for(int i = 1;i <= n;i++){
scanf("%d",&a[i]);
if(a[i] - i >= 0) b[++cnt] = a[i] - i;
else cur++;//一定需要改动的部分。。
}
memset(a,0,sizeof(a));
int now = 0;
a[now] = -1;
for(int i = 1;i <= cnt;i++){
if(b[i] >= a[now]){
a[++now] = b[i];
}
else{
int l = 1;
int r = now;
int ans;
while(l <= r){
int mid = (l + r) / 2;
if(a[mid] > b[i]){
r = mid - 1;
ans = mid;
}
else{
l = mid + 1;
}
}
a[ans] = b[i];
}
}
printf("%d\n",cur + cnt - now);
return 0;
}