题目链接:传送门
题目大意:
对序列a的任意一个数字进行赋值操作(除了下标属于setb的数字),使得序列 a 变成严格单增的序列,ai+1 > ai;
题目思路:
显然,对于一个严格单增的序列: ai+1 >= ai+1 , aj - ai >= j - i ;
对于 i ∈ setb ,ai 是不可修改的, 那么 i、j ∈ set_b , 若 aj - ai < j - i 则 无解;
接下来考虑一定有解的情况,
如果setb 为空 ,那么显然就可以直接求最长单调上升子序列,然后修改不属于最长子序列的数字;
如果setb 不为空, 修改后的序列 a 须满足 aj - ai >= j - i --> aj - j >= ai - i ,
那么构造序列 bi = ai - i,
分段求出每一段的最长单调不下降子序列即可。
那么,为什么需要构造序列b,而不能直接对序列a分段求最长上升子序列呢?
答案是显然的,假设 ai aj 是最长上升子序列的两个相邻元素,那么有 aj > ai ,但是 不一定满足 aj - ai >= j - i, 那么这个最长上升子序列不就不能满足之前的必要条件。因此,直接求LIS ,是无法保证筛选出来的子序列是一定满足aj - ai >= j - i的, 所以才要构造序列b 来保证aj - j >= ai - i。
代码:
1 #include<bits/stdc++.h> 2 #pragma GCC optimize(2) 3 using namespace std; 4 typedef long long LL; 5 typedef unsigned long long uLL; 6 typedef pair<int,int> pii; 7 typedef pair<LL,LL> pLL; 8 typedef pair<double,double> pdd; 9 const int N=5e5+5; 10 const int M=8e5+5; 11 const int inf=0x3f3f3f3f; 12 const LL mod=1e8+7; 13 const double eps=1e-8; 14 const long double pi=acos(-1.0L); 15 #define ls (i<<1) 16 #define rs (i<<1|1) 17 #define fi first 18 #define se second 19 #define pb push_back 20 #define eb emplace_back 21 #define mk make_pair 22 #define mem(a,b) memset(a,b,sizeof(a)) 23 LL read() 24 { 25 LL x=0,t=1; 26 char ch; 27 while(!isdigit(ch=getchar())) if(ch=='-') t=-1; 28 while(isdigit(ch)){ x=10*x+ch-'0'; ch=getchar(); } 29 return x*t; 30 31 } 32 int a[N],s[N],b[N]; 33 int main() 34 { 35 int n=read(),k=read(); 36 for(int i=1;i<=n;i++) a[i]=read()-i; 37 for(int i=1;i<=k;i++) b[i]=read(); 38 a[b[0]=0]=-inf,a[b[k+1]=n+1]=inf; 39 int flag=0; 40 for(int i=2;i<=k;i++) 41 if(a[b[i]]<a[b[i-1]]) flag=1; 42 if(flag) return 0*printf("-1 "); 43 int top=0,ans=0; 44 for(int i=0;i<=k;i++) 45 { 46 for(int j=b[i];j<b[i+1];j++) 47 { 48 if(top==0||s[top]<=a[j]) s[++top]=a[j]; 49 else 50 { 51 int pos=upper_bound(s+1,s+top+1,a[j])-s; 52 if(pos>1) s[pos]=a[j]; 53 } 54 } 55 ans+=(upper_bound(s+1,s+top+1,a[b[i+1]])-s)-1; 56 top=0; 57 } 58 printf("%d ",n-ans+1); 59 return 0; 60 }