cf 1437E. Make It Increasing

题目链接:传送门

题目大意:

对序列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\n");
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",n-ans+1);
59     return 0;
60 }
View Code

 

posted @ 2020-11-05 22:10  DeepJay  阅读(125)  评论(0编辑  收藏  举报