ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

7月清北学堂培训 Day 1

2019-07-13 14:00:35  阅读:345  来源: 互联网

标签:R4 Si 学堂 Day 算法 L3 清北 我们 贪心


基础算法

 1. 模拟算法

面向测试算法

模拟算法的关键就是将人类语言翻译成机器语言。

要做到以下两点:

1.优秀的读题能力;

2.优秀的代码能力;

 

程序流程图:

读入,循环处理指令,输出;

读题是很重要的,我们要考虑到用什么样的方法,怎么写;

 

 

主要就是要看懂四条规则然后往里面填数就好了,好像很简单,那就看这个题:

我们要先抓住核心部分:

手里有n张牌,有k(k<?)个规则,每个规则可以打出一定的牌,请问要打出最小多少次牌;

一个明显的深搜:

void dfs(剩下多少张牌没打last,打了多少次牌ans)

{

   if(last==0)    //牌打完了

      回溯

   if(k条规则)

    ……

}

 

模拟题更强调的就是选手的代码能力,其特点是:题目特烦,细节超多,代码极长;

考验的全部都是选手写代码的基本功:

1.写长代码都不出错的能力;

2.多方面全地考虑问题;

前者要求我们有一个良好的代码习惯,而后者则要求我们在做题时头脑有清晰的逻辑;

注意标准形式缩进;

 

一个笑话:

 

所以写长代码的要领在于一遍就写对!

Solution:

模块化结构(如何去思考一个问题?);

没想清楚时不动笔,画程序逻辑图;

写完一部分就检查一部分;最好一次AC;

在赛场上检验自己的程序是否正确的方式有两种:

1.造数据;

2.对拍;

对拍其实就是模拟算法的一种应用;

因为暴力算法的本质就是模拟(大雾)

 

2.贪心算法

贪心算法的数学原理:局部最优得到全局最优。

在每一个状态下,都选择当前的最优解而不考虑全局的影响;

爬山算法能较好地体现贪心的思想;

如何求解一个函数的最值?

贪心算法要满足两个条件:

1.  决策没有后效性;

2.  不会陷入局部最优解;

 

一般数据很大的题目,一般考虑用贪心,因为贪心的复杂度挺低的;

一般贪心算法会让你求最优解

做法:先找规律,看能否找到贪心的规律,然后找反例去验证;

标准做法:要么往下走,要么往上走,当我们走到顶峰的时候发现无论再往哪走都不是最优解了;

 

但如果函数长这个样子的话,那么就会陷入局部最优解了:

 

根据贪心的数学背景我们在做贪心题目的时候一般有两种策略:

1.把一个问题划分成很多子问题,对于每个子问题直接求最优解,然后合成一个最优解;

2.对于当前局面,搜索所有的可能的“临近局面”,选择最优的局面进行转移;

 

例如部分背包问题,我们按照每个物品的性价比往里面放直至塞满;

贪心在OI中更像是一种思路而不是一个确切的算法;

贪心一般用于求最优化问题,但是最优化问题还有很多算法——动态规划与搜索;

没有很好的方法去一下子区分一个最优解究竟是搜索+剪枝,还是动态规划还是贪心;

这个时候就很依赖经验的积累以及对题目性质的把握(触类旁通)

贪心最最重要的地方就是找反例,一般做题的过程中就在思考规律 -> 寻找反例 -> 找到算法或者重新思考的循环中度过;

平时遇到的贪心策略题都要仔细地咀嚼并记忆,这是你以后做其他题的根基;

 

贪心的经典问题:

例一:

考虑按照巧克力的价钱从小到大排序,然后在不多买巧克力的前提下能买就买;

这就意味着我们在买第 i 块巧克力的时候,前面比它更便宜的巧克力已经买完了;

证明的话很简单:假如你可以花 ai 元钱使第 i 头奶牛开心,同样你也可以花 aj 元钱使第 j 头奶牛开心,既然都是使1头牛开心了,你当然是花的钱越少越好,这样省下钱来买其他的巧克力能使更多的奶牛开心;

 

例二:

我们先不考虑取模的情况,我们枚举 S1~Sn,对于每个Si 我们去找在它前面最小的那个数,做差求最大值就好了;

现在考虑取模的情况,那么不再单单地找S前面最小的那个数了,而是找最接近Si 的数;

因为我们要考虑的是 Si - S和 Si - S+ Mod(如果Si < Sj 的话) 最大的那个;

我们可以偷懒用 set,先二分查找到第一个大于Si 的元素,然后找到最接近的数就好了;

 

例三:

先画出一个时间轴,将每个活动看作是一个个线段,要保证每个线段不能有重复的部分,问最多放几个线段;

考虑按照结束时间从小到大排序,然后我们从后往前枚举时间 i,枚举所有右端点小于等于 i 的线段,取其中左端点最大的;

均摊一下后,时间复杂度应该是O(n);

 

例四(喷水装置):

安利一下之前的博客

我们发现这个圆实际有用的就是与矩形相交的四个点所形成的矩形(下图中红色部分):

那么这个题就转化成了简单的线段覆盖问题;

我们固定右端点 i,然后找所有右端点大于等于 i 的区间(要覆盖 i 点),取其中左端点最小的,然后 i =这个左端点,继续上步操作直至覆盖整个区间。

 

例五:

首先考虑到“在x轴上画圆看能覆盖哪几个岛屿”这个想法是不现实的,我们要转化成线段覆盖之类的问题:

我们可以以每个岛屿为圆心画圆,这样的话会交x轴于两点,那么说明在这两点间的任意一点画圆都会覆盖这个岛屿;每个岛屿画一个圆就对应了一段线段,那么问题就转化成选尽量少的点使所有的线段内都有点包含;

这其实就是简单的区间选点的问题,先按照每个区间的左端点从小到大排序,对于每个区间,如果区间范围内有点那就跳到下一个区间里,否则就在区间最后的一个位置上放上点(贪心策略,这样能使这个点尽可能的多利用)。

 

例六:

lyd:这不是sb题吗?

先按 d [ i ] 从小到大排序,然后再按 (a [ i ] - b [ i ])从大到小排序。 

 

例七:

先预处理 k 以内的阶乘,然后从大到小枚举阶乘,n 能减就减,看看最后能否减到 0;

证明:

如果我们到了 k!< n,如果我们不减去 k!的话,我们后面∑ i!(1<= i <= k-1)都到不了 k!,那么肯定是分解不完的,所以我们要选上 k!。

这个方法类似我们在将十进制转化成二进制的过程;

 

例八:

如果可以的话一定要把最大的数提到最前面,然后发现剩下的数的顺序没变,那么我们就变成了部分序列求最大字典序,我们仍然按照上面的思路,尽量把最大的往前提,这样求出的字典序一定是最大的。

 

例九:

这个题是最小化最大值的问题,显然用二分。

我们先看怎么计算每个大臣获得的奖赏:1

Money= L* L2 * L*…… * Li / Ri ,L 和 R 表示大臣左手上和右手上的数字;

所以看起来我们要求一个前缀积了,Si = L1 * L2 * L3 *……* Li-1 ,注意这里由于数据过大需要采用高精运算;

考虑到相邻的两个大臣交换位置并不会对前面和后面的大臣造成影响,只会对交换的这两位大臣的奖赏造成影响,所以我们来讨论一下怎么换更优:

假设我们原来的大臣是这样排列的:

设S=L1 * L2

第三位大臣的奖赏:S / R3 ;

第四位大臣的奖赏:S * L3 / R

答案就是:max(S / R3,S * L3 / R4 ) ;

 

交换第三位和第四位大臣就是这样了:

第三位大臣的奖赏:S * L4 / R3 ;

第四位大臣的奖赏:S / R

答案就是:max(S / R4,S * L4 / R3) ;

比较一下哪个更优,PK大赛现在开始:

max(S / RS * L3 / R4 ) PK    max(S / R4,S * L4 / R3) 

首先我们看蓝色部分是一定小于绿色部分的,所以我们就可以拆掉max了,于是就成了:

S * L3 / R4   PK    S * L4 / R3 

同时除以S:  L3 / R4   PK     L4 / R3   

同时乘R3R4: L3 * R3    PK     L4 * R4   

也就是说,我们尽量让 Li * Ri 小的放前面;

那么对于整个序列,我们也按照这个规则走,那么不就是将 L* R从小到大排序即可?  

那么这个题就做完了。

 

标签:R4,Si,学堂,Day,算法,L3,清北,我们,贪心
来源: https://www.cnblogs.com/xcg123/p/11179922.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有