题面

CF1437E Make It Increasing

给 \(n\) 个数 \(a_i\),固定 \(k\) 个下标 \(b_i\),求只修改不在 \(b_i\) 中的下标的值使 \(a_i\) 严格单调递增的最少修改次数。

数据范围:\(1\le n\le 5\cdot 10^5\),\(0\le k\le n\)。


题解

分成 \(k+1\) 段做没有问题,蒟蒻的做法是线段树维护 dp

旁边老爷的做法是区间长度减去最长上升子序列长度,蒟蒻没想到,还想了单调队列优化好久。

题目转化为对于一个区间,第一个元素最后一个元素固定的最少修改次数。

把 \(a_i\) 减去 \(i\),就变成非严格单调递增了。

设 \(f_i\) 表示不修改 \(i\) 的前缀最少修改次数。

\[f_i=\min_{j=1,a_j\le a_i}^{i-1} (f_j+i-j-1)\Longrightarrow f_i=i-1+\min_{j=1,a_j\le a_i}^{i-1}( f_j-j)
\]

所以可以建一个 \(a_i\) 值域线段树,值为 \(f_i-i\)。

\(f_i\) 的值就是当前线段树 \([0,a_i]\) 之间的最大值 \(+i-1\)。

每次求出 \(f_i\) 后在 \(a_i\) 上更新 \(f_i-i\) 即可。


代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
#define mp(a,b) make_pair((a),(b))
#define x first
#define y second
#define bg begin()
#define ed end()
#define sz(a) int((a).size())
#define pb(a) push_back(a)
#define R(i,a,b) for(int i=(a),i##E=(b);i<i##E;i++)
#define L(i,a,b) for(int i=(b)-1,i##E=(a)-1;i>i##E;i--)
const int iinf=0x3f3f3f3f;
const ll linf=0x3f3f3f3f3f3f3f3f; //Data
const int N=5e5+2;
int n,a[N],dn,d[N],k,b[N],ans; //SegmentTree
const int tN=N<<2;
#define mid ((l+r)>>1)
int mn[tN];
void build(int k=0,int l=0,int r=dn){
mn[k]=iinf; if(r-l==1) return;
build(k*2+1,l,mid),build(k*2+2,mid,r);
}
void pushup(int k){mn[k]=min(mn[k*2+1],mn[k*2+2]);}
void fixmn(int x,int v,int k=0,int l=0,int r=dn){
if(r<=x||x+1<=l) return;
if(r-l==1) return mn[k]=min(mn[k],v),void();
fixmn(x,v,k*2+1,l,mid),fixmn(x,v,k*2+2,mid,r),pushup(k);
}
int rangemn(int x,int y,int k=0,int l=0,int r=dn){
if(r<=x||y<=l) return iinf; if(x<=l&&r<=y) return mn[k];
return min(rangemn(x,y,k*2+1,l,mid),rangemn(x,y,k*2+2,mid,r));
} //DP
int tmp[N];
int dp(int* arr,int len){
R(i,dn=0,len) d[dn++]=arr[i];
sort(d,d+dn),dn=unique(d,d+dn)-d;
R(i,0,len) tmp[i]=lower_bound(d,d+dn,arr[i])-d;
build(),fixmn(tmp[0],0); int res=-1;
R(i,1,len){
res=rangemn(0,tmp[i]+1)+i-1;
fixmn(tmp[i],res-i);
}
// R(i,0,len) cout<<arr[i]<<' ';cout<<'\n';
// R(i,0,len) cout<<f[i]<<' ';cout<<'\n';
// cout<<f[len-1]<<'\n';
return res;
} //Main
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n>>k,a[0]=-iinf,a[n+1]=+iinf;
R(i,1,n+1) cin>>a[i],a[i]-=i;
R(i,0,k) cin>>b[i];
R(i,1,k)if(a[b[i]]<a[b[i-1]]) cout<<-1<<'\n',exit(0);
if(k==0) ans=dp(a,n+2);
else {
ans+=dp(a,b[0]+1);
R(i,1,k) ans+=dp(a+b[i-1],b[i]-b[i-1]+1);
ans+=dp(a+b[k-1],n-b[k-1]+2);
}
cout<<ans<<'\n';
return 0;
}

祝大家学习愉快!

题解-CF1437E Make It Increasing的更多相关文章

  1. 【题解】Greatest Common Increasing Subsequence

    [题解]Greatest Common Increasing Subsequence vj 唉,把自己当做DP入门选手来总结这道题吧,我DP实在太差了 首先是设置状态的技巧,设置状态主要就是要补充不漏 ...

  2. LeetCode题解之Longest Continuous Increasing Subsequence

    1.题目描述 2.问题分析 从每一个num[i]往前扫描即可. 3.代码 int findLengthOfLCIS(vector<int>& nums) { ){ return n ...

  3. Lintcode397 Longest Increasing Continuous Subsequence solution 题解

    [题目描述] Give an integer array,find the longest increasing continuous subsequence in this array. An in ...

  4. LeetCode题解之 Increasing Order Search Tree

    1.题目描述 2/问题分析 利用中序遍历,然后重新构造树. 3.代码 TreeNode* increasingBST(TreeNode* root) { if (root == NULL) retur ...

  5. LeetCode题解之Longest Increasing Subsequence

    1.题目描述 2.题目分析 使用动态规划,在计算以每个字符结尾的最长子序列. 3.代码 int lengthOfLIS(vector<int>& nums) { ){ ; } ve ...

  6. Codeforces Round #160 (Div. 1) 题解【ABCD】

    Codeforces Round #160 (Div. 1) A - Maxim and Discounts 题意 给你n个折扣,m个物品,每个折扣都可以使用无限次,每次你使用第i个折扣的时候,你必须 ...

  7. LeetCode Longest Increasing Path in a Matrix

    原题链接在这里:https://leetcode.com/problems/longest-increasing-path-in-a-matrix/ Given an integer matrix, ...

  8. 【题解】【数组】【查找】【Leetcode】Search in Rotated Sorted Array

    Suppose a sorted array is rotated at some pivot unknown to you beforehand. (i.e., 0 1 2 4 5 6 7 migh ...

  9. 300. Longest Increasing Subsequence

    题目: Given an unsorted array of integers, find the length of longest increasing subsequence. For exam ...

随机推荐

  1. linx 内核 并发与同步 1

    内核并发来源: 1.硬件中断和异常:中断服务程序和被中断的进程可能发生并发访问资源 2.软中断和tasklet,软中断和taklet随时都可能倍调度执行,从而打断当前正在执行 进程的上下文. 3.内核 ...

  2. tcp syn-synack-ack 服务端接收ack

    TCP 服务端 接收到ack tcp_v4_rcv() -> tcp_v4_do_rcv() -> tcp_v4_hnd_req() + tcp_child_process()tcp_v4 ...

  3. 1、线性DP 354. 俄罗斯套娃信封问题

    354. 俄罗斯套娃信封问题 https://leetcode-cn.com/problems/russian-doll-envelopes/ 算法分析 首先我们从两种情况来讨论这个问题: w无重复值 ...

  4. fcntl函数用法——复制文件描述符

    文件描述符复制和输出重定向dup() 用最小的文件描述符来复制,从0开始搜素.复制文件描述符后,最小文件描述符指向被复制描述符指向的文件.dup2(int oldfd,int newfd) 强制用ne ...

  5. 判断机器是big-endian、little-endian

    联合体union和大小端(big-endian.little-endian):下边示范了一种用途,代表四个含义的四个变量,但是可以用一个int来操作,直接int赋值,无论内存访问(指针大小的整数倍,访 ...

  6. 《GNU_makefile》——第八章 内嵌函数

    函数可以带参数,函数的展开方式和变量展开一样,函数的返回结果替换调用函数的文本. 1.函数的调用 $(FUNCTION ARGUMENTS) 或者: ${FUNCTION ARGUMENTS} FUN ...

  7. explain命令---查看mysql执行计划

    引言: 实际项目开发中,由于我们不知道实际查询的时候数据库里发生了什么事情,数据库软件是怎样扫描表.怎样使用索引的,因此,我们能感知到的就只有 sql语句运行的时间,在数据规模不大时,查询是瞬间的,因 ...

  8. JWT 实战

    上一篇我们讲解了 JWT 的基本原理和结构 你了解JWT吗?,接下来我们具体实战一下! 1. 引入依赖 <!--引入jwt--> <dependency> <groupI ...

  9. Java 开发之 Lombok 必知必会

    转载链接地址:https://juejin.im/post/5cf3edf7e51d454f71439c79 1. 前言 在目前众多编程语言中,Java 语言的表现还是抢眼,不论是企业级服务端开发,还 ...

  10. 关于Java集合框架,这篇讲的还算不错了,建议大家看看!

    集合框架 为什么要用集合而非数组: 虽然数组是保存一组对象最有效的方式,但是数组具有固定尺寸,但在写程序时并不知道将需要多少个对象.而集合能够自动地调整自己的尺寸. 打印数组时,必须使用Arrays. ...