一道不难的DP题,主要是为了总结这类最优化题的思路;同时还学到了一个新操作

传送门:$>here<$

题意

给出一个长度为$N$的序列,要求最多使用s个数字进行量化(有损压缩),即代替原数字:使得量化后各个被代替的数与代替的数的差的平方之和最小。

数据范围:$n \leq 100, s \leq 10$

Solution

动态规划的常规思路

容易发现肯定选择数值相近的一些数字用一个数字取替代,所以肯定先排序。

排序完后就是一个简单的dp题了。$dp[i][j]$表示前$i$个数字,使用$j$个数字量化的最小误差。当前决策一定关于第$i$个数字有关,问题在于究竟这一段要多长。在枚举一个k,转移就很明显了:

$dp[i][j]=Min\{dp[k][j-1]+quantize(k+1,i)\}$

究竟用什么来做量化的值

问题转化为了如何求$quantize$函数。就这道题的范围来看,从最小到最大枚举也是没有问题的。但实际上有$O(1)$方法。

设我们选择$m$来量化,也就是说函数$y=\sum\limits_{i=l}^{r}(m-a[i])^2$最小。问题转化为求此函数的最小值。

这是个二次函数,所以展开后直接求导(或直接使用顶点公式),找到顶点的$x$坐标即可。

$y=\sum\limits_{i=l}^{r}(m-a[i])^2=(r-l+1)m^2-2m\sum\limits_{i=l}^{r}a[i]+\sum\limits_{i=l}^{r}a[i]^2$

当$y'=2(r-l+1)m-2\sum\limits_{i=l}^{r}a[i]=0$时

$m=\frac{\sum\limits_{i=l}^{r}a[i]}{r-l+1}$

这就是平均值!由此我们得到结论:当利用平均值来当量化值时,差的平方之和最小。

透过题解看本质

其实对于这类最优化dp问题,可以看做是递归问题。dp的本质是记忆化搜索,只不过可以利用递推来实现。当我搜到这一步时需要枚举来决策当前需要多长的一段来量化,而剩余的则不需要递归,而是直接利用之前做好的最优子结构。这就是dp为什么比dfs快了。其实dp就是暴力,它终究需要考虑所有需要且可能的情况。

my code

具体在实现的时候通过统计前缀和以及平方的前缀和来$O(1)$完成求解。注意把$m$代入求误差时也要利用前缀和。

注意平均值应该四舍五入。

/*By DennyQi 2018*/
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int MAXN = ;
const int MAXM = ;
const int INF = 0x3f3f3f3f;
inline int Max(const int a, const int b){ return (a > b) ? a : b; }
inline int Min(const int a, const int b){ return (a < b) ? a : b; }
inline int read(){
int x = ; int w = ; register char c = getchar();
for(; c ^ '-' && (c < '' || c > ''); c = getchar());
if(c == '-') w = -, c = getchar();
for(; c >= '' && c <= ''; c = getchar()) x = (x<<) + (x<<) + c - ''; return x * w;
}
int T,N,s;
int a[MAXN],dp[MAXN][],sum[MAXN],ssqr[MAXN];
inline int calc(int l, int r, int m){
int res = ;
res += m*m * (r-l+);
res += ssqr[r] - ssqr[l-];
res -= *m*(sum[r]-sum[l-]);
return res;
}
inline int quantize(int l, int r){
int m = (sum[r]-sum[l-]) / (r-l+);
return Min(calc(l,r,m), calc(l,r,m+));
}
inline int Solve(){
sort(a+,a+N+);
sum[] = ssqr[] = ;
for(int i = ; i <= N; ++i){
sum[i] = sum[i-] + a[i];
ssqr[i] = ssqr[i-] + a[i] * a[i];
}
memset(dp,INF,sizeof(dp));
for(int i = ; i <= s; ++i) dp[][i] = ;
for(int i = ; i <= N; ++i){
for(int j = ; j <= s; ++j){
for(int k = ; k < i; ++k){
dp[i][j] = Min(dp[i][j], dp[k][j-] + quantize(k+,i));
}
}
}
return dp[N][s];
}
int main(){
// freopen(".in","r",stdin);
T = read();
while(T--){
N = read(), s = read();
for(int i = ; i <= N; ++i){
a[i] = read();
}
printf("%d\n", Solve());
}
return ;
}

「Algospot」量化QUANTIZE的更多相关文章

  1. 「Algospot」津巴布韦ZIMBABWE

    同时考验对状压DP和数位DP的理解: 传送门:$>here<$ 题意 给出一个数字$e$,现在对$e$通过$m$进行变换得到$x$:变换的要求是:1.只能改变原数字$e$各个数位的顺序(可 ...

  2. 「Algospot」龙曲线DRAGON

    一道考验思维的好题,顺便总结求第k大问题的常规思路: 传送门:$>here<$ 题意 给出初始串FX,每分形一次所有X替换为X+YF,所有Y替换为FX-Y.问$n$代字符串第$p$位起长度 ...

  3. 「译」JUnit 5 系列:扩展模型(Extension Model)

    原文地址:http://blog.codefx.org/design/architecture/junit-5-extension-model/ 原文日期:11, Apr, 2016 译文首发:Lin ...

  4. 面试都在问的「微服务」「RPC」「服务治理」「下一代微服务」一文带你彻底搞懂!

    ❝ 文章每周持续更新,各位的「三连」是对我最大的肯定.可以微信搜索公众号「 后端技术学堂 」第一时间阅读(一般比博客早更新一到两篇) ❞ 单体式应用程序 与微服务相对的另一个概念是传统的「单体式应用程 ...

  5. 《Offer一箩筐》一份高质量「简历」撰写指南,望打扰!!

    「MoreThanJava」 宣扬的是 「学习,不止 CODE」. 如果觉得 「不错」 的朋友,欢迎 「关注 + 留言 + 分享」,文末有完整的获取链接,您的支持是我前进的最大的动力! Hi~ 这里是 ...

  6. 「译」JUnit 5 系列:条件测试

    原文地址:http://blog.codefx.org/libraries/junit-5-conditions/ 原文日期:08, May, 2016 译文首发:Linesh 的博客:「译」JUni ...

  7. JavaScript OOP 之「创建对象」

    工厂模式 工厂模式是软件工程领域一种广为人知的设计模式,这种模式抽象了创建具体对象的过程.工厂模式虽然解决了创建多个相似对象的问题,但却没有解决对象识别的问题. function createPers ...

  8. 「C++」理解智能指针

    维基百科上面对于「智能指针」是这样描述的: 智能指针(英语:Smart pointer)是一种抽象的数据类型.在程序设计中,它通常是经由类型模板(class template)来实做,借由模板(tem ...

  9. 「JavaScript」四种跨域方式详解

    超详细并且带 Demo 的 JavaScript 跨域指南来了! 本文基于你了解 JavaScript 的同源策略,并且了解使用跨域跨域的理由. 1. JSONP 首先要介绍的跨域方法必然是 JSON ...

随机推荐

  1. GoLang simple-project-demo-02

    GoLang 有很多种数据类型:字符型,整型,浮点型,布尔型.下面是基础例子: package main import "fmt" func main() { fmt.Printl ...

  2. 并发concurrent---3

    背景:并发知识是一个程序员段位升级的体现,同样也是进入BAT的必经之路,有必要把并发知识重新梳理一遍. ConcurrentHashMap:在有了并发的基础知识以后,再来研究concurrent包.普 ...

  3. 通过Hutool 调用远程API接口(POST/GET)

    背景:需要调用第三方接口,开启某项任务,用Hutool代替了HttpClient 调用第三方接口,简单粗暴. 代码如下: import java.util.Date; import org.apach ...

  4. iOS----------适配iOS12

    library not found for -lstdc++.6.0.9 原因是苹果在XCode10和iOS12中移除了libstdc++这个库,由libc++这个库取而代之,苹果的解释是libstd ...

  5. 利用AccessibilityService自动获取微信号(Android)

    前言: 最近遇到一个需求,要求写一个小插件,能够自动在微信的页面弹出一个窗口,展示用户的相关信息(与我们公司有关的信息,方便运营快速了解用户信息). 当时我第一反应是不可能,如果能够在别的app中获取 ...

  6. git常用命令总结--廖雪峰老师Git教程命令总结

    学习了廖雪峰老师的Git教程之后的命令总结,重点关于git和远程仓库的东西. 如果没有学过,这是传送门 下面这个图很重要 一.git初始化本地仓库和配置 echo "想输入到文件的内容,一般 ...

  7. 移动端click延迟和tap事件

    一.click等事件在移动端的延迟 click事件在移动端和pc端均可以触发,但是在移动端有延迟现象. 1.背景 由于早期移动设备浏览网页时内容较小,为了增强用户体验,苹果公司专门为移动设备设计了双击 ...

  8. 阿里云OCR图片转换成文字识别调用

    using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Drawing; using S ...

  9. shell编程企业级实战

    如何才能学好Shell编程 为什么要学习shell编程 Shell是Linux底层核心 Linux运维工作常用工具 自动化运维必备基础课程 学好shell编程所需Linux基础 熟练使用vim编辑器 ...

  10. Python--day09(内存管理、垃圾回收机制)

    昨天内容回顾 1.  操作文件的三个步骤: 1.  打开文件:硬盘的空间被操作系统持有,文件对象被用用程序持续 2.  操作文件:读写操作 3.  释放文件:释放操作系统对硬盘空间的持有 2.  基础 ...