递增
传送门:
P3902 递增 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
思路
刚开始看到这道题以为是求出最长上升子列直接减一下,
感觉是暴力秒杀
但是这道题的数据范围最多可以a50分
那么我们就要思考解决方法了
首先数的范围是到1e9,但是数最多只有1e5个所以可以考虑离散化(这叫不叫离散化蒟蒻也不太清楚)
那我们应该怎么离散化呢
这是个关键点!这里我们把dp的下标当作当前数的最长子序列
dp中的元素表示当前数
那么每次如果我下一个元素大于当前元素我是不是可以下个元素的长度是不是就等于前一个元素长度+1
如果不等于那么我们可以查找一个正好小于的情况,然后更新当前长度下的数
(这样复杂度要小于N^2但是还是差不多,所以我们还需要优化,优化过会提)
我们继续来思考为什么要这样做,这样做的依据是什么?
依据是没有依据……
因为每次都是当前最大的,如果当前数大于上个数,那么原长度+1是不是就是当前最大的了(有一点贪心的思想);如果当前不是最大的那么就找一个最大的。
错误……错误,我一开始也是这样想的但是其实是想错了
就是每次找一个比自己的数小的但是又是当前长度最长的,+1就是我要的当前数的最长递增子序列
那么其实我只需要优化来找的过程就能解决了
要查找了O(N)肯定不显示,O(N^2)肯定超时,一般O(NlogN)一想就是二分
为了方便思考,其他思路写在代码注释上
有问题请评论或私信我,谢谢!
AC code
// Problem:
// P3902 递增
//
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P3902
// Memory Limit: 125 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include<iostream>
#include<algorithm>
//#include<cstdio>
#define ll long long
#define endl '\n'
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define per(i,a,b) for(int i=(a);i>=(b);i--)
#define N 100010 //1e6+100
using namespace std;
int n,res;
double a[N],dp[N];
int main(){
cin>>n;
rep(i,1,n) cin>>a[i];
rep(i,1,n){
if(a[i]>dp[res]){
//如果当前数比当前最长子序列的最后一个数要大,那么新的最长子序列长度就是这个子序列的长度+1,而当前最长子序列的最后一个数就是这个数
res++;//当前最长子序列长度=原来最长子序列长度+1
dp[res]=a[i];//当前最后一个数是这个数
}else{
//为什么可以用二分,首先dp是一个递增序列,
//因为每次赋值dp的时候都是当a[i]>dp[res]的时候把a[i]赋值给dp[res+1]的
//其次更新的时候,每次是把第一个a[i]<=dp[]的位置更新成a[i]后面本来就是>=a[i]的数我更新的当前位置再小是>=a[i]的所以他肯定也是不改变增减性的,为什么这样更往下看;
//递增讲完了,那么讲讲为什么这样更的话可以把每个数放好使这个数成为本属于他当前子序列的最后一个数
//在思路中提过dp的下标就表示当前最长子序列长度
//那么是不是只要大于某个最长子序列的最后一个数的后一个元素(当然前提是递增),那这个后一个元素就是当前数可以组成的最长子序列了。
int l=0,r=res+1;
while(l+1<r){
//这种二分板子可能比较少有人用,那可以用自己的板子,或者用 lower_bound()函数
//只要保证我们的找dp中大于等于a[i]的数就行
int mid=(l+r)/2;
if(a[i]>dp[mid])l=mid;
else r=mid;
}
//l是比当前数小的哪一个元素,那么r也就是l+1就是这个属于这个数的最长子序列长度
dp[r]=a[i];//更新当前最长子序列下的最后一个数
//一定要更新,因为如果不更新的话比如原来dp[r]的位置是5然后a[i]是4后面还有一个a[i]是5,那么如果不更新a[i]为5的那个数最长上升子序列就是r了不会是正确的值(就小了),更改了之后就会变正常
}
}
cout<<n-res;//题目是至少需要改几个数使他变为递增序列,那么我们只要n-最长子序列长度就行
return 0;
}
有问题请评论或私信我,谢谢!
有共同学习需求的可以加入洛谷团队:https://www.luogu.com.cn/team/66731