E. Make It Increasing
首先让ai=ai−ia_i=a_i-iai=ai−i这样可以是严格单增变成单调增。
参考官方题解
首先不难得出如果我们根据不同修改的位置分割成若干段,那么若干段是互不影响的,我们只需要求出每一个若干段修改次数的最小值。
如果当前考虑l~r这一段,这里l和r都是不能修改的位置,我们要使得al≤al+1→r−1≤ara_l\leq a_{l+1\to r-1}\leq a_ral≤al+1→r−1≤ar,对于原来不在此范围内的数一定需要修改,所以只需要考虑在此范围内的数如何修改的最少!实际上是选择最长的上升子序列,剩下的修改即可。而最长上升子序列我们可以O(nlogn)解决。
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#pragma GCC optimize(2)
#include<set>
#include<map>
#include<cmath>
#include<stack>
#include<queue>
#include<random>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<unordered_map>
#include<unordered_set>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=500010;
int a[N],b[N],n,k;
int main()
{IO;int T=1;//cin>>T;while(T--){cin>>n>>k;for(int i=1;i<=n;i++) cin>>a[i];for(int i=1;i<=n;i++) cin>>b[i];a[0]=-1e9,a[n+1]=2e9;for(int i=0;i<=n+1;i++) a[i]-=i;b[k+1]=n+1;b[0]=0;bool ok=1;int res=0;for(int i=0;i<=k;i++){int l=b[i],r=b[i+1];if(a[l]>a[r]){ok=0;break;}vector<int> lis;for(int j=l+1;j<r;j++)if(a[l]<=a[j]&&a[j]<=a[r]){auto pos=upper_bound(lis.begin(),lis.end(),a[j]);if (pos==lis.end()) lis.push_back(a[j]);else *pos=a[j];//这里会修改值}res+=(r-l-1)-lis.size();}if(!ok) res=-1;cout<<res<<'\n';}return 0;
}
反思:md我知道那个小trick使得严格变成非严格,但是还是没能运用,还是见的太少,没运用这个小trick导致我的判断不合法时尤为困难。
题解中的最长上升子序列代码好简洁,学习了!
贪心,考虑当前的数,那么替换第一个大于它的数并不影响原来维护序列的单调性,而且答案不会更差!
要加油哦~