【笔记】收集一些有意思的题目

https://codeforces.com/contest/1605/problem/D

读了个假题

Codeforces - 1603C - Extreme Extension

原题链接:https://codeforces.com/contest/1603/problem/C

官方的题解相对难懂,是要从后往前维护一个dp[i][x]表示把第i个数分解为最小值为x时,这个数被包含的区间长度,容易看出来x越小,能被包含的区间长度就越长。这个想法挺复杂的。

评论区里面有一个简单的解法:https://codeforces.com/blog/entry/96460?#comment-855425

只考虑一个固定的序列。注意到一个数字要被尽可能平均分配,设将a[j]分配出来的最小值为v[j],被分配的次数为t[j],显然t[j]=a[j]/v[j+1]的上整,v[j]=a[j]/t[j]的下整。对一个序列[1,n],从n反向贪心就可以求出[n..1]的所有的t和v的值,对于所有以n为结尾的子数组,产生的总贡献即为(t[n]-1)n+(t[n-1]-1)(n-1)+...(t[1]-1)*1。这样对于每个固定的序列,都能够O(n)求出以他结尾的子数组的贡献。考虑往序列最末尾加一个新的数,这样会导致tv数组可能会从后往前被更新(v[n]变了),但是a[j]/v[j+1]只有O(sqrt(C))种取值,所以这个每个位置的t至多会被更新O(sqrt(C))次。倘若某一个t没有被更新,那么显而易见的前面的数字也不会再更新。

启发

  1. 这道题明显是可以从后往前dp的,一次性把需要的所有的t和v都计算出来并缓存起来,但是这样弄得思考贡献的时候不够显然。
  2. 这个题解的启发就在于不一次计算出所有需要的状态,而是等到新加一个数使得前面的状态更新的时候再从后往前更新。
  3. 利用总更新的次数限制来达到正确的复杂度。
  4. 1e5的上限很可能和根号有关。
  5. 可以先设想一个暴力算法,再想办法优化复杂度(数据结构题常见套路),复用一下相邻状态的信息。

Codeforces - 1602B - Divine Array

原题链接:https://codeforces.com/contest/1602/problem/B

这道题比较有意思,非常容易看出来每个步骤之后,要么数组保持不动,要么不同的数字减少至少1次,所以至多进行n次就会进入不动状态。复杂度O(n^2)。

但是有一个更精确的上界,假如某次操作后数组减少了1个不同的数字(合并了两个),那么这两个数字的频次至少分别为1,而在合并之后的频次至少为2。在第1次操作之后,若没有进入不动状态,那么最小的频次就会至少为2,第2次操作后就至少为4,所以操作次数的复杂度上界为O(logn)。

原文地址:https://www.cnblogs.com/purinliang/p/15485379.html