OMG 我辛辛苦苦打的笔记被吃掉了 只能转载我们涵神的了 反正我们写的差不多

附上涵神原文:传送门

  • 背景
  • 搜索到DP的过渡
    • 搜索的艰辛
    • 记忆化出现了
  • DP的基础
    • DP的实现方法

      • 例题

        • 题面
        • 分析
      • 再谈LCS
        • 题面
        • 回忆一般的LCS
        • code
        • 正解算法
        • code
  • DP的优化
    • 单调性优化

      • 例题

        • 题面
        • 分析
        • code
      • 例题
        • 题面
        • 分析
        • code
    • 斜率优化
      • 例题

        • 分析
        • code

背景

MZX大佬来这边的路真是艰辛啊!说好九点的飞机,十一点就能到,结果晚点到十点。到早上我们才知道他晚点到了一点,四点才到的海亮教育园。所以上午就看了万能的区间DP。然后下午终于出现在了讲台上面……
12:24大佬开始卖弱
12:30终于开始讲了

搜索到DP的过渡

搜索的艰辛

搜索的时间复杂度是指数级的。我们如果把dp的题目用搜索做的话简直会爆炸。例如最经典的01背包,如果不会dp,我们只能用dfs来枚举每个物品选不选,选的加进vector里面。好一点的dfs可以只记录已经选的物品质量和价值;最后加可行性剪枝和最优性剪枝,可以稍微好一点。

记忆化出现了

搜索的时间复杂度越来越不能征服人类日益增长的需求了!因为人们的cpu不能发展的那么快(摩尔定律都学过吧)。所以这时候一个救世主出现了——记忆化搜索。
dfs的最优性剪枝:记录下前i个物品总重量为w时候的最大价值和,或者价值为v时候的最小总重量。(记忆化搜索)Dfs可以带三个参数:dfs(物品件数,物品总重,物品总价值),类似地我们可以加一个f数组,来记录这种状态:f[i][w]=v来代表前i个物品质量w时候的最大价值v。本质就是我们在搜索的时候只记录对后面的选择有影响的状态,以及该状态下的最优值。这种方法适用于很多0/1选择的问题,比如lis。记录xx状态时候的最优值这种做法其实就是dp,只不过我们把指数级的算法剪成了多项式。Dp的关键在于写出状态转移方程,就像这样 f[i]=max/min{……} f[i]=max/min\{……\};
Dp的思考方式:先用dfs思考一下,再用参数写出状态数组。最后写出状态转移方程。

DP的基础

DP就是这样应运而生的。

DP的实现方法

Dp有两种实现方法:递推和记忆化搜索,后面就体现出了这个搜索——“剪枝”算法的本质。

例题

题面

给定一个RxC(R,C≤500)的滑雪场,每个格子都有高度,每个格子只能滑向(四联通)相邻的比它低的格子,求最大的滑行长度(可以任意确定起点).

分析

很明显,如果搜索,那么对选择有影响的状态只有当前位于哪个格子,所以就可以设置状态为当前格子,最优值就是以这个格子为起点的最大滑行长度。
一个格子的最优值依赖于哪些格子呢?比它低的。
所以我们可以dfs递归搜索,加上记忆化就能ac了。说实话这道题目用dp还不如写dfs呢。。。

再谈LCS

LCS——最长公共子序列。大家都会把。这里会介绍一种具有特殊性质的LCS。

题面

给定两个长度为5n的序列,1…n每个数字出现5次,求最长公共子序列,n≤1e5。

回忆一般的LCS

方法一:1、dfs法:不断分解组合。
2、DP法:从规模小的子问题推到总问题。
我们需要枚举两个串的每一位,在这道题目中时间复杂度是 O(n2) O(n^2),明显超时。
具体做法是这样:
如果a[i-1]=b[i-1]那么
F[i][j]=max(f[i][j],f[i−1][j−1]+1); F[i][j]=max(f[i][j],f[i-1][j-1]+1);
如果不相等,那么
F[i][j]=max(f[i−1][j],f[i][j−1]); F[i][j]=max(f[i-1][j],f[i][j-1]);

code

#include<bits/stdc++.h>
using namespace std;
inline int read()
{
    int num=0;
    char c=getchar();
    for(;c<'0'||c>'9';c=getchar());
    for(;c>='0'&&c<='9';c=getchar())num=num*10+c-'0';
    return num;
}
int n,m,a[302000],b[302000],f[5001][5001];
int main()
{
    n=read();
    m=read();
    for(int i=1;i<=n;i++)
    a[i]=read();
    for(int i=1;i<=m;i++)
    b[i]=read();
    for(int i=2;i<=n+1;i++)
    for(int j=2;j<=m+1;j++)
    {        f[i][j]=max(f[i-1][j],f[i][j-1]);
        if(a[i-1]==b[j-1])
        f[i][j]=max(f[i][j],f[i-1][j-1]+1);
    }
    printf("%d",f[n+1][m+1]);
    return 0;
}

正解算法

但是恭喜,只能拿部分分!!!o(╥﹏╥)o许多同学内心是崩溃的。这道题目我们需要再观察一下这道题目。这道题目有一个特殊性质:因为这道题目每个数会且只会出现5次。所以我们发现上面code的那个判断两个是否相等的if语句值为真的总共会有 5×5×n 5\times5\times n。我们可以变换一下思路。为啥要把整个f数组都算出来呢?我们如果把f数组画出来。我们会发现,是一张 5n×5n 5n\times 5n的表格,每行只有5个元素是相互匹配的。我们可以只填匹配上的点。时间复杂度就降成了 O(n) O(n)!!多么美妙!但是我们发现并没有一个可以直接填点的方法。我们可以借用一下数据结构这个好玩意儿。
这里我们采用线段树,每次查询的时间复杂度是 O(logn) O(\log n)那么总的时间复杂度是 O(nlogn) O(n \log n)。
我们每填完一行我们都要修改一下线段树。让每一个结点j代表以j的横坐标和纵坐标为边的矩阵最大值。然后填值的时候就利用线段树结点的值来进行计算和判断。

code

【待补全】

DP的优化

DP的时间复杂度一般都是二次级别的,有时候数据超过10000就可能会超时。所以我们需要进行一些有的没的的优化。

单调性优化

在很多时候,dp的决策往往是具有单调性的。我们来看个例题:

例题

题面

超级教主
题目描述
LHX教主很能跳,因为Orz他的人太多了。教主跳需要消耗能量,每跳1米就会消耗1点能量,如果教主有很多能量就能跳很高。 教主为了收集能量,来到了一个神秘的地方,这个地方凡人是进不来的。在这里,教主的正上方每100米处就有一个能量球(也就是这些能量球位于海拔100,200,300……米处),每个能量球所能提供的能量是不同的,一共有N个能量球(也就是最后一个能量球在N×100米处)。教主为了想收集能量,想跳着吃完所有的能量球。教主可以自由控制他每次跳的高度,接着他跳起把这个高度以下的能量球都吃了,他便能获得能量球内的能量,接着吃到的能量球消失。教主不会轻功,教主不会二段跳,所以教主不能因新吃到的能量而变化此次跳跃的高度。并且教主还是生活在地球上的,所以教主每次跳完都会掉下来。 问教主若要吃完所有的能量球,最多还能保留多少能量。
输入格式
第1行包含两个正整数N,M,表示了能量球的个数和LHX教主的初始能量。
第2行包含N个非负整数,从左到右第I个数字依次从下向上描述了位于I×100米位置能量球包含的能量,整数之间用空格隔开。
输出格式
仅包括一个非负整数,为教主吃完所有能量球后最多保留的能量。
样例数据
input
3 200
200 200 200
output
400
【样例说明】 第1次跳100米,得到200能量,消耗100能量,所以落地后拥有300能量。 第2次跳300米,吃到剩下的第3棵能量球,消耗拥有的300能量,得到400能量。 若第1次跳200米,第2次跳300米,最后剩余300能量。
数据规模与约定
【数据规模】 对于10%的数据,有N≤10;   对于20%的数据,有N≤100; 对于40%的数据,有N≤1000; 对于70%的数据,有N≤100000; 对于100%的数据,有N≤2000000。 保证对于所有数据,教主都能吃到所有的能量球,并且能量球包含的能量之和不超过2^31-1。

分析

我们先考虑用dfs做,明显会有:void dfs(int l,int E)
并且来个记忆化f[i]代表I*100处的最小花费能量。总能量是一定的,我们止血药最小化跳的高度总和就可以了,也就是存在 f[i]=min{f[j]+100∗i} f[i]=min\{f[j]+100*i\}我们把所有不含j的项提出来 =min{f[j]}(E+W[j]−f[j]≥100∗i)+100∗i =min\{f[j]\}(E+W[j]-f[j]\ge100*i)+100*i
(ps:W[j]表示w的前缀和)
但是这道题目我们不需要使用单调队列,止血药记录满足上述()中的条件的最小的j就可以了。代码实现:

int j=0;
for(int i=1;i<=n;i++)
{
while(E+W[j]-f[j]<100&&j<i)
j++
if(i==j)
{
//输出不可能的情况。
}
F[i]=f[j]+100*i;
}

code

【待补全】

例题

题面

取货 题目描述
某公司估计市场在第i个月对某产品的需求量为Ui,已知在第i月该产品的订货单价为di,上个月月底未销完的单位产品要付存贮费用m,假定第一月月初的库存量为零,第n月月底的库存量也为零。
问如何安排这n个月订购计划,才能使成本最低?每月月初订购,订购后产品立即到货,进库并供应市场,于当月被售掉则不必付存贮费。假设仓库容量为S。
输入格式 第1行:n,m,S (0<=n<=50,0<=m<=10,0<=S<=10000) 第2行:U1,U2,…,Ui,…,Un
(0<=Ui<=10000) 第3行:d1,d2,…,di,…,dn (0<=di<=100) 输出格式 只有1行,一个整数,代表最低成本
样例数据 input 3 1 1000 2 4 8 1 2 4 output 34

分析

这道题目明显是一道dp题目。我们令f[i][j]表示第i个月存了j件货物的总代价。
所以有状态转移方程:
f[i][j]=minf[i−1][k]+k×m+(u[i]+j−k)×w[i](k≤u[i]+j)=minf[i−1][k]+k×(m−w[i])+(u[i]+j)×w[i] f[i][j]=min{f[i-1][k]+k\times m+(u[i]+j-k)\times w[i]}(k≤u[i]+j) =min{f[i-1][k]+k\times (m-w[i])}+(u[i]+j)\times w[i]
我们把大括号内的表达式定义为V(k)。
那么如果V(y)比V(x)更优而且x比y更早不合法,那么x这个决策在y加入中就失去了存在的意义。x生命失去了希望。

code

【待补全】

斜率优化

斜率优化就是把一些决策通过描点在一个二维平面上画出直线,通过斜率的单调性来解决。

例题

题目描述
N个任务排成一个序列在一台机器上等待完成(顺序不得改变),这N个任务被分成若干批,每批包含相邻的若干任务。
从时刻0开始,这些任务被分批加工,第i个任务单独完成所需的时间是Ti。在每批任务开始前,机器需要启动时间S,而完成这批任务所需的时间是各个任务需要时间的总和(同一批任务将在同一时刻完成)。
每个任务的费用是它的完成时刻乘以一个费用系数Fi。请确定一个分组方案,使得总费用最小。
例如:S=1;T={1,3,4,2,1};F={3,2,3,3,4}。如果分组方案是{1,2}、{3}、{4,5},则完成时间分别为{5,5,10,14,14},费用C={15,10,30,42,56},总费用就是153。
输入格式
第一行是N(1<=N<=50000)。 第二行是S(0<=S<=50)。 下面N行每行有一对数,分别为Ti和Fi,均为不大于100的正整数,表示第i个任务单独完成所需的时间是Ti及其费用系数Fi。
输出格式
一个数,最小的总费用。
样例数据
input
5
1
1 3
3 2
4 3
2 3
1 4
output
153

分析

【待补全】

code

【待补全】

2017.10.28闵神讲课DAY1相关推荐

  1. 【长沙集训】2017.10.28

    1 抄代码 1.1 问题描述 J 君是机房的红太阳,每次模拟她总是 AK 虐场.然而在 NOIP2117 中,居然出现了另一位 AK 的选手 C 君! 这引起了组委会的怀疑,组委会认为 C 君有抄袭 ...

  2. 2017.10.26试题(NOIP DAY1难度)

    T1:为爱追寻 [问题描述] 话说一年半以前,紫萱学姐展开了对杨廷学长的追求.在经历了不懈的努力之后,学姐终于成为了一名--金牌单身狗.但是这位痴情的少女并没有放弃,于是决定在保送之后继续进行这项征程 ...

  3. 2017.10.28 管道取珠 失败总结

    这个题有一个新套路:  ∑ai^2 要知道一般的计数题是∑ai,,所以这多乘了一个自己有什么意义呢? 于是想到,两两枚举,加起来正好是ai^2:: 所以就有一个想法,枚举两种取法, 然后就是插数dp, ...

  4. 2017.10.28 排序 思考记录

    这个题有一种套路,就是大小关系转化成01串,这样就变成了二分检验问题,, 就是把排序变成区间修改,然后单点查询.. 把所有比他小的赋成0,比他大的赋成1 然后判断要求位是0还是1来判断答案与当前值的大 ...

  5. 2017.10.28 压缩 思考记录

    这个题首先要知道M和R不是栈的搭配,是贪心的搭配,,就是向左找到第一个M.. 如 abababab cdcdcdcd abababab cdcdcdcd   = abRRcdcdcdcdR != Ma ...

  6. 【265天】跃迁之路——程序员高效学习方法论探索系列(实验阶段23-2017.10.28)...

    实验说明 从2017.10.6起,开启这个系列,目标只有一个:探索新的学习方法,实现跃迁式成长 实验期2年(2017.10.06 - 2019.10.06) 我将以自己为实验对象. 我将开源我的学习方 ...

  7. 大搜车Java面试 2017.10.30

    大搜车Java面试 2017.10.30 杭州余杭区办公环境一般,两层一栋的办公楼,但是开发工位是连成一片的没有卡位一说.比较拥挤. 面试两轮技术面,总共耗时3小时,各种等待就有1小时,最后人事说三天 ...

  8. 2017.10.12 记者招待会

    2017.10.12  记者招待会 记者招待会 看到这个题目,你会不会吓一跳?一名普通的员工,哪里会参加记者招待会?是的,不是我参加.你脆弱的小心脏可以简单的修正一下,因为后面还有一个劲爆的消息:学生 ...

  9. Alluxio Meetup 2018.10.28北京进行,欢迎交流

    #搜狗如何将Spark Shuffle迁移到上千台Alluxio机器集群,服务知识图谱? #七牛云如何用Alluxio在云端搭建通用深度学习平台? #京东又是如何定制基于普雷斯托的查询平台? 欢迎大家 ...

最新文章

  1. IBM与思科在融合型基础设施领域实现另一突破
  2. python读写csv确定编码格式_Python使用utf8编码读写csv文件
  3. js中时间戳与日期时间之间的相互转换
  4. nodejs安装及环境配置_nodeJS安装和环境变量的配置
  5. 堆排序 C++代码实现及思想 排序过程输出 恋上数据结构笔记
  6. Python 运算符 if和while的使用
  7. pytorch中的切片时的省略号
  8. AnotherRedisDesktopManager下载地址
  9. 举例什么时候会用到 call(), apply()
  10. Date Picker和UITool Bar的使用
  11. __va_rounded_size
  12. 托管式服务网格:多种类型计算服务统一管理的基础设施
  13. cad批量打印_CAD插件批量打印3.5.9
  14. 读书笔记|《金字塔原理》第二章
  15. C# 批量修改文件名称
  16. b站投稿 您的稿件未能成功转码。原因:该视频时长不足1秒,请检查视频时长并尝试重新上传。解决办法
  17. JQuery模拟MAC任务栏放大效果
  18. 基于C# winform的操作系统课程设计:SPOOLING假脱机输入输出技术模拟
  19. Python获取并输出当前日期时间
  20. c语言中fflush作用,详解C语言fflush()函数的使用

热门文章

  1. 华为鸿蒙手机系统什么时候开始更新_华为鸿蒙OS适配计划曝光,一起看看你的手机什么时候可以升级...
  2. 中国区块链50城之香港:新政之下STO或成热点 | 链塔智库
  3. 相爱者彼此可以做的100件事情
  4. oracle联合主键效率,Oracle主键与复合主键的性能分析
  5. RecyclerView最后一条显示不全或显示部分的问题解决
  6. GBase 8a集群之智能索引
  7. unity 本地MP3文件读取
  8. 个人掌上游戏机diy——之二,组合
  9. C 小树快长高 SDUT
  10. AMF(Action Message Format)简介