Description

给定一长度为 \(n\) 的数列 \(a\),可将 \(a_i\) 改为任意整数 \(k\),代价为 \(\mid a_i-k\mid\)。

问最少改变多少个数能把它变成一个单调严格上升的序列。

输出最少需要改变的数的个数,以及在改变的数最少的情况下,最小的代价和。

\(1\leq n\leq 3.5\times 10^4,1\leq a_i\leq 10^5\)。

Solution

Part 1

Solve Problem 1:需要改变的数最少,则需保留的数要尽可能多。考虑取一个补集,问题转化为求最多保留多少个数。

对于两个数 \(a_i,a_j\)(不妨设 \(i<j\)),若可同时保留 \(i\) 和 \(j\),则 \(a_i,a_j\) 需满足:

  • \(a_i<a_j\)(显然)。

  • 改变 \([i+1,j-1]\) 内的数能够使 \([i,j]\) 严格单调上升。所以 \(a_j-a_i\geq j-i\)。移项可得,\(a_i-i\leq a_j-j\)。

构造数列 \(b_i=a_i-i\),问题转化为求 \(b\) 的最长不降子序列。可 \(O(n\log n)\) 求得。

Part 2

Solve Problem 2:使 \(a\) 单调上升的代价,就是使 \(b\) 单调不降的代价。

考虑在 \(b\) 的最长不降子序列中,任意两个相邻的元素。设它们 \(b\) 中的位置分别为 \(l,r\),则一定 不存在 \(i\in[l,r]\),使得 \(b_l\leq b_i\leq b_r\)。否则取上 \(i\),保证合法,而且可以使最长不降子序列更长。

所以对于 \(\forall i\in[l,r]\),\(b_i<b_l\) 或 \(b_i>b_r\)。

考虑如何改变 \(b_i\) 的值,能使序列合法且代价和最小。

结论:存在一个数 \(k\in [l,r]\):对于 \(\forall i\in[l,k]\),把 \(b_i\) 改成 \(b_l\)。对于 \(\forall i\in[k+1,r]\),把 \(b_i\) 改成 \(b_r\)。此时代价和最小。

假设 \([l,r]\) 之间有 \(n\) 个数。

  • 当 \(n=1\) 时,结论显然成立。(因为 \(b_i<b_l\) 或 \(b_i>b_r\),\(b_i\) 改为 \(b_l\) 或 \(b_r\) 显然比改为取值在 \([b_l,b_r]\) 之间的数优)

  • 当 \(n>1\) 时:

    • 前 \(n-1\) 个数一半改为 \(b_l\) 一半改为 \(b_r\):当 \(b_n>b_r\) 时,显然将 \(b_n\) 改为 \(b_r\) 比较优。当 \(b_n<b_l\) 时,若 \(b_n\) 不改为 \(b_r\) 改为了 \(b_l+k\)(\(0\leq k\leq b_r-b_l\)),为了使序列单调不降,前面所有改为 \(b_r\) 的数都应改成 \(b_l+k\)(设这样的数有 \(x\) 个)。\(x\times (b_r-(b_l+k))+((b_l+k)-b_n)=xb_r-(x-1)(b_l+k)-b_n\geq b_r-b_n\),所以此时 \(b_n\) 改为 \(b_r\) 更优。

    • 前 \(n-1\) 个数全改为 \(b_l\) 或 \(b_r\):略。

Part 3

令 \({dp}_i\) 表示最后一位是 \(b_i\) 时单调不降的最小代价。

枚举 \(j\),枚举的 \(j\) 需满足:

  • \(j<i,b_j<b_i\)。

  • 以 \(b_j\) 结尾的最长不降子序列长度 \(=\) 以 \(b_i\) 结尾的 \(-1\)。

枚举分界点 \(k\),有:

\(\displaystyle{dp}_i=\min\{{dp}_j+\sum\limits_{p=j+1}^k\mid b_p-b_j\mid+\sum\limits_{p=k+1}^{i-1}\mid b_p-b_i\mid\}\)

即:对于 \(p\in[j+1,k]\),将 \(b_p\) 改为 \(b_j\)。对于 \(p\in[k+1,i-1]\),将 \(b_p\) 改为 \(b_i\)。

前缀和优化转移即可。

Code

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=4e4+5;
int n,a[N],b[N],len,f[N],g[N],dp[N],pre[N],suf[N];
vector<int>v[N]; //v[i]: 记录长度为 i 的最长不降子序列的结尾
void solve(int l,int r,int L,int R){
pre[l]=suf[r+1]=0;
for(int i=l+1;i<=r;i++) //前缀和
pre[i]=pre[i-1]+abs(b[i]-L);
for(int i=r;i>=l+1;i--) //后缀和
suf[i]=suf[i+1]+abs(b[i]-R);
}
signed main(){
scanf("%lld",&n);
for(int i=1;i<=n;i++)
scanf("%lld",&a[i]),b[i]=a[i]-i;
b[0]=-1e9,b[++n]=1e9; //边界。加上前后最小值最大值方便操作。最大值不要设太大,不然算前缀和的时候可能会爆。
f[1]=b[1],len=1,g[1]=1,v[1].push_back(1);
for(int i=2;i<=n;i++){ //O(n log n) 求最长不降子序列
if(b[i]>=f[len]) f[++len]=b[i],g[i]=len;
else{
int x=upper_bound(f+1,f+1+len,b[i])-f;
f[x]=b[i],g[i]=x; //g[i]: 以第 i 个数结尾的最长不降子序列的长度
}
}
for(int i=0;i<=n;i++) v[g[i]].push_back(i);
memset(dp,0x3f,sizeof(dp)),dp[0]=0;
for(int i=1;i<=n;i++)
for(int p=0;p<(int)v[g[i]-1].size();p++){ //如果 b[j] 要拼上前面合适的 b[i],就去前面找长度为 g[i]-1 且能拼上的
int j=v[g[i]-1][p]; //以 b[j] 结尾的 最长不降子序列长度 = 以 b[i] 结尾的 -1
if(j>i||b[j]>b[i]) continue; //j<i,b[j]<=b[i] 才行
solve(j,i,b[j],b[i]);
for(int k=j;k<i;k++) //枚举分界点 k
dp[i]=min(dp[i],dp[j]+pre[k]+suf[k+1]);
}
printf("%lld\n%lld\n",n-len,dp[n]);
return 0;
}

「HAOI 2006」数字序列的更多相关文章

  1. OKR-Periods of Words「POI 2006」

    题目描述 串是有限个小写字符的序列,特别的,一个空序列也可以是一个串.一个串 P 是串 A 的前缀,当且仅当存在串 B,使得 A = PB.如果 P != A 并且 P 不是一个空串,那么我们说 P  ...

  2. Solution -「HAOI 2018」「洛谷 P4491」染色

    \(\mathcal{Description}\)   Link.   用 \(m\) 种颜色为长为 \(n\) 的序列染色,每个位置一种颜色.对于一种染色方案,其价值为 \(w(\text{出现恰 ...

  3. 「BZOJ 4565」「HAOI 2016」字符合并「区间状压DP」

    题意 给一个长度为\(n(\leq 300)\)的\(01\)串,每次可以把\(k(\leq 8)\)个相邻字符合并,得到新字符和一定分数,最大化最后的得分 题解 考虑设计dp:\(dp[S][i][ ...

  4. 「HAOI 2018」染色

    题目链接 戳我 \(Solution\) 观察题目发现恰好出现了\(s\)次的颜色有\(k\)种,不太好弄. 所以我们设\(a[i]\)表示为恰好出现了\(s\)次的颜色有至少\(i\)种的方案数,然 ...

  5. Solution -「CEOI 2006」「洛谷 P5974」ANTENNA

    \(\mathcal{Description}\)   Link.   给定平面上 \(n\) 个点,求最小的能覆盖其中至少 \(m\) 个点的圆半径及一个可能的圆心.   \(n\le500\),坐 ...

  6. 「算法笔记」树形 DP

    一.树形 DP 基础 又是一篇鸽了好久的文章--以下面这道题为例,介绍一下树形 DP 的一般过程. POJ 2342 Anniversary party 题目大意:有一家公司要举行一个聚会,一共有 \ ...

  7. loj#2128. 「HAOI2015」数字串拆分 矩阵乘法

    目录 题目链接 题解 代码 题目链接 loj#2128. 「HAOI2015」数字串拆分 题解 \(f(s)\)对于\(f(i) = \sum_{j = i - m}^{i - 1}f(j)\) 这个 ...

  8. Libre 6010「网络流 24 题」数字梯形 (网络流,最大费用最大流)

    Libre 6010「网络流 24 题」数字梯形 (网络流,最大费用最大流) Description 给定一个由n 行数字组成的数字梯形如下图所示.梯形的第一行有m 个数字.从梯形的顶部的m 个数字开 ...

  9. 「长乐集训 2017 Day10」划分序列 (二分 dp)

    「长乐集训 2017 Day10」划分序列 题目描述 给定一个长度为 n nn 的序列 Ai A_iA​i​​,现在要求把这个序列分成恰好 K KK 段,(每一段是一个连续子序列,且每个元素恰好属于一 ...

随机推荐

  1. A Child's History of England.41

    When intelligence of this new affront [hit in the face, c-o-n-frontation!] was carried to the King i ...

  2. Learning Spark中文版--第五章--加载保存数据(1)

      开发工程师和数据科学家都会受益于本章的部分内容.工程师可能希望探索更多的输出格式,看看有没有一些适合他们下游用户的格式.数据科学家可能会更关注他们已经使用的数据格式. Motivation   我 ...

  3. 大数据学习day22------spark05------1. 学科最受欢迎老师解法补充 2. 自定义排序 3. spark任务执行过程 4. SparkTask的分类 5. Task的序列化 6. Task的多线程问题

    1. 学科最受欢迎老师解法补充 day21中该案例的解法四还有一个问题,就是当各个老师受欢迎度是一样的时候,其排序规则就处理不了,以下是对其优化的解法 实现方式五 FavoriteTeacher5 p ...

  4. Linux 设置时区

    一.查看和修改Linux的时区 1. 查看当前时区命令 : "date -R" 2. 修改设置Linux服务器时区方法 A命令 : "tzselect" 方法 ...

  5. 转 GSON

    转 https://www.jianshu.com/p/75a50aa0cad1 GSON弥补了JSON的许多不足的地方,在实际应用中更加适用于Java开发.在这里,我们主要讲解的是利用GSON来操作 ...

  6. ViewStub应用

    在开发应用程序的时候,会遇到这样的情况,在运行时动态的根据条件来决定显示哪个View或哪个布局,可以把可能用到的View都写在上面,先把他们的可见性设置为View.GONE,然后在代码中动态的更改它的 ...

  7. Oracle命名规则

    1.长度不能超过三十个字符 2. 不要使用Oracle关键字 比如:id  name  table 3. 不能使用数字开头 包含:数字  字母  下划线 美元符号 4.  建议用 英文单词,不要去用中 ...

  8. NSData NSDate NSString NSArray NSDictionary 相互转化

    //    NSData  NSDate NSString NSArray NSDictionary json NSString *string = @"hello word"; ...

  9. [BUUCTF]PWN——[V&N2020 公开赛]babybabypwn

    [V&N2020 公开赛]babybabypwn 附件 步骤: 例行检查,64位程序,保护全开 本地试运行一下,看看程序的大概情况 64位ida载入,看一下main函数 sub_1202()函 ...

  10. UVA10079 Pizza Cutting 题解

    Content 求用 \(n\) 条直线最多能将平面分成多少块区域. 多组输入,以一个负数结束. 数据范围:\(0\leqslant n\leqslant 2.1\times 10^8\). Solu ...