给个$n<=2000$长度数列,可以把每个数改为另一个数代价是两数之差的绝对值。求把它改为单调不增or不减序列最小代价。


话说这题其实是一个结论题。。找到结论应该就很好做了呢。

手玩的时候就有感觉,改造出来的数列的元素会不会全是原来数列里有的数?弄了几组发现没问题,但是还是踟蹰不前,不敢下手。。然后我就智障的换思路了。。。这个故事告诉我们发现一个暂时没找到反例的结论一定要大胆实践,反正交到OJ上不要钱。

所以这题结论就上面那个。具体证明呢。。我不会。。。

然后就简单了啊。有个很好想的状态$f[i][j]$第$i$位填数字$j$(因为$j$是只在原数组中出现的,所以可以离散化压缩状态为2000个)。于是每次枚举之,在上一位中找小于当前值的转移过来。

$f[i][j]=min(f[i-1][k]+|A[j]-a[i]|)$       $1<=k<=j$

然后k那一维做个前缀max减一维枚举就n方啦。

Upd:补证明。其实lyd书上是有的,但是并没看懂。后来由于thx学长帮助,大概理解了(%%%)。

数学归纳法。

对于$n=1$,显然成立。

对于$n=k-1$时假设其满足由原数列的数构成最优解。那么,考虑对于$n=k$。

当$A_n ≥ B_{n-1}$时(B为之后的数列)显然直接用$A_n$最优。

当$A_n ≤ B_{n-1}$时有两种选择一种是由上一个$B_{n-1}$继续过来。

一种是把当前$B_i$向下调整向下调整时,前面的构造好的数列要被迫下调。

那么假设下调至$x$。前面连着的一段应当也调为$x$。

(到这里都是lyd原话)

为什么统一调为$x$,前面构造好的数为什么不会变的比$x$更小从而更优?

如果之前的变得更小就更优的话,那我在之前就应当将它改为更小值保证最优了,而不是现在。

也就是说只能统一改为一个数$x$。

这时候用结论,这一段每个数与$x$差的绝对值要最小化,做多了就知道这是个中位数问题。

那么取这段数中的$mid$一定是可以保证代价最小的。

综上,$B_n$在保证最优的情况下只可能用A数列中有的数。

Upd2:见code下面。

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#define dbg(x) cerr<<#x<<" = "<<x<<endl
#define ddbg(x,y) cerr<<#x<<" = "<<x<<" "<<#y<<" = "<<y<<endl
using namespace std;
typedef long long ll;
template<typename T>inline char MIN(T&A,T B){return A>B?A=B,:;}
template<typename T>inline char MAX(T&A,T B){return A<B?A=B,:;}
template<typename T>inline T _min(T A,T B){return A<B?A:B;}
template<typename T>inline T _abs(T A){return A<?-A:A;}
template<typename T>inline T _max(T A,T B){return A>B?A:B;}
template<typename T>inline T read(T&x){
x=;int f=;char c;while(!isdigit(c=getchar()))if(c=='-')f=;
while(isdigit(c))x=x*+(c&),c=getchar();return f?x=-x:x;
}
const int N=+;
ll f[N][N],ans;
int a[N],A[N],n,m;
inline void dp(){
for(register int i=;i<=n;++i){
ll minx=f[i-][];
for(register int j=;j<=m;++j)MIN(minx,f[i-][j]),f[i][j]=minx+_abs(A[j]-a[i]);
}
} int main(){//freopen("test.in","r",stdin);//freopen("test.out","w",stdout);
read(n);
for(register int i=;i<=n;++i)A[i]=read(a[i]);
sort(A+,A+n+),m=unique(A+,A+n+)-A-;
dp();
ans=f[n][];
for(register int i=;i<=m;++i)MIN(ans,f[n][i]);
reverse(a+,a+n+);
dp();
for(register int i=;i<=m;++i)MIN(ans,f[n][i]);
printf("%lld\n",ans);
return ;
}

Upd2

这题还有对应的拓展。(以及lyd付的思考题)

  • 把原序列改为不严格单调增序列,至少改多少数?
  • $ans=len-maxlen_{不下降子序列}$。原因很简单,保证有一个最长的不降序列,才能保证剩下的修改最少嘛。
  • 把原序列改为严格单调增序列,至少改多少数?
  • 令$B_i=A_i-i$。$ans=len-maxlen_{B的不下降子序列}$。这个比较重要。
  • 首先要考虑的问题是,严格单调递增→若原数列中两数相差超过下标差时,这段数一定要改一些数,否则改掉也“挤不下”。这是问题所在。
  • 要保证“挤得下”,就必须$A_j-A_i>=j-i $  $(i<j)$。即$A_j-j>=A_i-i$,才有严格递增。
  • 更准确地说,要$A_i<A_{i+1}\Leftrightarrow A_i \leqslant A_{i+1}-1\Leftrightarrow A_i-i\leqslant A_{i+1}-(i+1)\Leftrightarrow B_i\leqslant B_{i+1}$
  • 这是一个><号转≥≤的重要方法。所以要严格大于,我构造上述序列B,即可将其转化为大于等于。
  • 两者是等价的。
  • 方法是https://blog.csdn.net/guhaiteng/article/details/52549991的大佬的。tql%%%。

然后这题就可以顺带切掉了。

另外,将一开始问题的要求改为严格递增的最小代价,该怎么求?转化。同理,用上述方法构造序列。由于在原A序列和构造的B序列上修改代价是一样的,所以保证B满足不严格单调并且代价最小也就保证了A的严格单调。

然后相关题目是CF714E。

当然还有一个神仙的log做法。左偏树。我不会。逃。(要用log的做的题

poj3666/CF714E/hdu5256/BZOJ1367(???) Making the Grade[线性DP+离散化]的更多相关文章

  1. LG2893/POJ3666 「USACO2008FEB」Making the Grade 线性DP+决策集优化

    问题描述 LG2893 POJ3666 题解 对于\(A\)中的每一个元素,都将存在于\(B\)中. 对\(A\)离散化. 设\(opt_{i,j}\)代表\([1,i]\),结尾为\(j\)的最小代 ...

  2. POJ - 3666 Making the Grade(dp+离散化)

    Description A straight dirt road connects two fields on FJ's farm, but it changes elevation more tha ...

  3. poj 3666 Making the Grade(dp离散化)

    Making the Grade Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 7068   Accepted: 3265 ...

  4. POJ3666 线性dp_离散化_贪心

    POJ3666 线性dp_离散化_贪心 就DP而言这个题不算难,但是难就难在贪心,还有离散化的思想上 题目大意:n个土堆,问你最少移动多少单位的图,可以使得这n个土堆变成单调的 dp[i][j]表示前 ...

  5. LightOJ1044 Palindrome Partitioning(区间DP+线性DP)

    问题问的是最少可以把一个字符串分成几段,使每段都是回文串. 一开始想直接区间DP,dp[i][j]表示子串[i,j]的答案,不过字符串长度1000,100W个状态,一个状态从多个状态转移来的,转移的时 ...

  6. Codeforces 176B (线性DP+字符串)

    题目链接: http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=28214 题目大意:源串有如下变形:每次将串切为两半,位置颠倒形成 ...

  7. hdu1712 线性dp

    //Accepted 400 KB 109 ms //dp线性 //dp[i][j]=max(dp[i-1][k]+a[i][j-k]) //在前i门课上花j天得到的最大分数,等于max(在前i-1门 ...

  8. 动态规划——线性dp

    我们在解决一些线性区间上的最优化问题的时候,往往也能够利用到动态规划的思想,这种问题可以叫做线性dp.在这篇文章中,我们将讨论有关线性dp的一些问题. 在有关线性dp问题中,有着几个比较经典而基础的模 ...

  9. POJ 2479-Maximum sum(线性dp)

    Maximum sum Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 33918   Accepted: 10504 Des ...

随机推荐

  1. 【Web】[原创]ie6,7中td和img之间有间隙

    情形描述 开发工具:VS2010: 浏览器版本:IE6以上,火狐,谷歌: 页面布局设计:Table+Img布局: 项目预览问题:火狐,谷歌,IE8以上未出现问题,IE6,IE7图片之间有间隙. 分析原 ...

  2. 论文阅读 | Generating Fluent Adversarial Examples for Natural Languages

    Generating Fluent Adversarial Examples for Natural Languages   ACL 2019 为自然语言生成流畅的对抗样本 摘要 有效地构建自然语言处 ...

  3. 第五周课程总结&试验报告三

    第五周课程总结 一.第五周课程总结 1.this关键字 this可用于任何实例方法内指向当前对象,也可指向对其调用当前方法的对象,或者在需要当前类型对象引用时使用.当一个类的属性(成员变量)名与访问该 ...

  4. 生成一个水平+垂直居中的div

    这是前端布局经常用到的布局方式,水平垂直居中:面试也经常会问到. 一. 绝对定位实现居中 注意:使用绝对定位布局的时候,外层元素必须也设置有position属性,具体设置为什么值看具体情况.只要不是s ...

  5. [c++] SYSTEM_INFO

    SYSTEM_INFO,Win32 API函数GetSystemInfo所使用的结构体. 说明 SYSTEM_INFO结构体包含了当前计算机的信息.这个信息包括计算机的体系结构.中央处理器的类型.系统 ...

  6. Django在使用Mysql迁移数据库时,会报的错

    settings : DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'firstproject', ...

  7. selenium Grid2环境搭建和基本使用

    Selenium Grid简介 利用Selenium Grid可以使主节点(hub)的测试用例在不同主机即分支点(node)运行.可以使一份测试用例在不同环境下(操作系统.浏览器)执行自动化测试.Se ...

  8. ASP.NET Core WebApi使用Swagger生成API说明文档【xml注释版】

    ⒈新建ASP.NET Core WebAPi项目 ⒉添加 NuGet 包 Install-Package Swashbuckle.AspNetCore ⒊Startup中配置 using System ...

  9. C++学习 之 类的声明及成员的访问(笔记)

    1.类的声明 简单来说,属性以及对属性的操作的整合叫做类.要声明类可使用关键字class,并在它的后面定义类名,然后紧接着是属于该类的代码块{}.类的声明类似于函数声明,类的声明本身并不改变程序 的行 ...

  10. C++练习 | 单向链表类模板(包含类模板中静态变量初始化格式)

    #include <iostream> #include <string> using namespace std; template <class T> clas ...