【校内模拟】【18-10-24】 小C的数组 【DP】【二分】

题解

1.0 认(hu)真(luan)分析(建议跳过)

不就是维护相邻数字的差的最大值最小吗?简单~

  1. 把n-1个数对丢到优先队列里面,维护一下差值以及位置.
  2. 更新的时候就把靠前的值改了,然后丢掉,再把靠后的值与数对前面那个值合并一下丢进队列。
  3. 所有丢掉的数打上标记,然后最后扫一遍,这些有标记的地方取平均值即可。

我在说什么玩意儿
比如 7 3 8 9,k=1,丢进去(7,3) (3,8) (8,9),先把(3,8)拿出来,把3打标记(比如弄成inf),然后把(7,8)压回去。最后输出的时候扫一遍得到的是 7 inf 8 9,有inf的地方取前后两个值的中间值,如果是一串inf就用左侧数和右侧数的差值除以inf的个数。

然后我开开心心的爆零了

(上面这个算法为什么不对,博主暂时还给不出什么正经的证明(真是抱歉),如果哪位大佬能给出反例自然感激不尽~)

1.1 正解
70pts DP+二分

读题,发现我们要求的是最大值最小,那就应该自然想到二分答案。

不过这个check函数怎么写呢?

首先考虑,对于比二分出的mid还要大的Ai - Ai+1 ,我们肯定要进行更改,那么我们就记一个当前的数字是多少,记一个修改了多少次,再记一个现在的位置,就有了fi,j,k

如果连修改的机会都用完了还不能使Ai - Ai+1 <mid,那就把二分的下界调高;只要能有一种方案满足,我们就把二分的上界调低。

(当然要是不二分直接枚举就只有30pts了

100pts DP改进

思考一下,我们刚才的dp之所以得不到满分,就是因为这个数据范围变大了,我们没法用当前数字作为状态来转移了。

那如果我们记录不了修改的状态……我们记录下哪些地方不修改不就行了吗?

于是乎,用fi表示当前位置是第i个,这之前的所有数字全都修改,后面的数字也全部满足要求,需要修改多少个数字。

状态转移呢?

实际上也比较简单,我们从n开始倒推,那么对于状态fi,首先它前面的全部要改,其次它后面的、不符合要求的肯定也得改。

那啥时候他后面的要改呢?

对于 (j-i)*mid >= (Ai-Ai)的,我们可以得到转移 fi=min(fi,fj+j-i+1)。这个其实很好理解:如果两个值之间的差值大于了(j-i)*mid,你怎么改都不可能改出想要的答案,所以没法转移。而对于别的状态,我们取最小值转移就可以了。

所以就是 for(i=n;i>=1;i- -)里面加一个for(j=n;i>=i+1;j- -),最后转移出来的状态f1就是使得mid成立所需要的最小修改次数,再根据这个调整上下界就可以啦~

总结

首先是一定一定看到最大值最小这种东西就要用二分!然后再考虑如何去验证二分的答案是否正确,可以是搜索、DP、区间查询等等,总之只要能够检验答,都要试一试。

当然首先我们一定要想到二分

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章