前言

上午一场模拟赛(发布前很久,因为这题题解太长了),发现T3特别珂怕,打开题解,发现一行字:

不要再问了,再问就是CF 1240E

当场去世.jpg。

在下文中,我们记 \(A\) 为 \(a\) 数组中的最大值,在代码中就是 "_max" 。

题意简述

题目链接

给出一组 \(n\) 块木板以及它们的长度 \(a_i\),现在要切割出两块木板使之长度为 \(x\) ,切割 \(x\) 块木板使之长度为 \(y\)。

求 \(x \times y\) 的最大值。

题解

基本思想

我们有一个非常美妙的使用二分的 \(\Theta(Aln_Alog_A)\) 的做法,

但是我们今天要说的是一个比它优秀的 \(\Theta(Aln_A)\) 的算法。

为什么说是 \(ln_A\) ,因为 \(\sum_{i=1}^{n} n / i = ln_A\) (调和级数)。

对于几乎所有的做法,都有两个显然的思想,

枚举 \(y\) ,然后计算 \(x\);

贪心地把长度为 \(l\) 的木板分解为 \(l = tx + ky + \delta, t \in [0, 2]\) 其中 \(\delta\) 越小越好。

有了这个思想以后我们还需要按照 \(l / y\) 的值对木板分块(即块的区间 \([ ky, (k+1)y )\) )。

接下来我们可以来进行一波分类讨论。

两个 \(x\) 在同一块木板中被切割出



我们记 \(p_1, p_2\) 为两个点,且 \(p_1\) 距离它所在块的右端点比 \(p_2\) 更远。

可以证明, \(p_1\) 的决策一定劣于 \(p_2\) ,因为在抛去 \(ky\) 的情况下,

选择 \(p_2\) 所得的 \(x\) 显然更大。

那么我们从右往左扫描,设当前的块为 \(c\) 。

在式子 \(l = x + ky + \delta\),若当前的块为 \(c\) ,当前块往右的所有块(包括自己)里所在块右端点最远的点为 \(p\) 。

则定义\(x = (c \times y + p \% y) / 2\) ,剩下的部分给 \(ky\) 。

记 \(p\) 在 \(c\) 中的映射为 \(p'\),即 \(p' \in c\) 且 \(p' \equiv p \mod(y)\)(下文中的 \(p_1',p_2'\) 同理)。



具体如上图所示。

两个 \(x\) 分别在两块木板中被切割出

根据上面的结论,我们仍然从右往左扫描,设当前的块为 \(c\)。然后我们记,

当前块往右的所有块(包括自己)里所在块右端点最远的木板为 \(p_1\) 。

当前块往右的所有块(包括自己)里所在块右端点次远的木板为 \(p_2\) 。

那么我们总结出并讨论如下四种情况:

情况1、2

\(\quad \quad\)

我们在情况一内分类讨论,发现只有两种情况可能最优,

第一种是把 \(p_2\) 木板分解完全(即 \(=x + ky\),\(k\) 为 \(c\) 到 \(p_2\) 所在块跨越的块数),第二种是把 \(p_1\) 木板分解完全。

但是注意到如果 \(p_1\) 木板分解完全,那么 \(p_2\) 木板长度显然不够了,于是我们牺牲 \(p_2\) 木板裁出的一个 \(y\) ,来保证能够切除一个 \(x\) 。

再来考虑情况二,我们发现情况二的不同之处是, \(p_2\) 木板不能够牺牲一个 \(y\) 来保证切除 \(x\) 了(长度不足),

那么处理方法很简单,直接舍弃掉完全分解 \(p_1\) 方案(滑稽),只考虑完全分解 \(p_2\)。

您觉得讨论结束了?还有两种哦 QwQ 。

情况3:



我们发现情况3与情况1相同(显然易见还是将 \(p_1\) 或 \(p_2\) 分解完全)。

情况4



我们发现情况4与情况2相同(显然易见还是不能牺牲 \(p_2\) 的一个 \(y\))。

然后我们注意到计算的时候,\(x\) 不一定小于 \(y\)的个数,所以要取一个 \(min\) 。

代码

note: 我 CodeForces 账号是 \(lukelin\) 哦(所以不要说我的代码是copy的)。

注释是英文的,因为怕出玄学错误。

  1. /*
  2. author: lukelin
  3. note: I'm sorry that my English is poor.
  4. */
  5. #include <cstdio>
  6. // input data
  7. int a[500005];
  8. // make length -> pos & the prefix
  9. int cnt[1000005], prfc[1000005];
  10. int l1[1000005], l2[1000005];
  11. #define min(a,b) ((a<b)?a:b)
  12. #define max(a,b) ((a>b)?a:b)
  13. inline void swap(int &a, int &b){
  14. int tmp = a; a = b, b = tmp;
  15. }
  16. long long ans;
  17. inline void flush(int x, int cnty, int y){
  18. if (min(cnty, x) <= 1) return ;
  19. ans = max(ans, 1ll * min(cnty, x) * y);
  20. }
  21. int main(){
  22. int n, _max = 0; scanf("%d", &n);
  23. for (int i = 1; i <= n; ++i){
  24. scanf("%d", &a[i]), ++cnt[a[i]];
  25. if (_max < a[i]) _max = a[i];
  26. }
  27. int prfc_lim = _max << 1; //the max id we will use in prfc
  28. for (int i = 1; i <= prfc_lim; ++i) prfc[i] = prfc[i - 1] + cnt[i];
  29. l1[0] = l2[0] = -1;
  30. for (int i = 1; i <= prfc_lim; ++i){
  31. //l1 - the longest wood which less equal than i
  32. //l2 - the second longest wood which less equal than i
  33. if (cnt[i] >= 2) l1[i] = l2[i] = i;
  34. else if (cnt[i] == 1) l2[i] = l1[i - 1], l1[i] = i;
  35. else l1[i] = l1[i - 1], l2[i] = l2[i - 1];
  36. }
  37. for (int y = 2; y <= _max; ++y){
  38. int ycnt = 0;
  39. for (int c = 1; c * y <= _max; ++c){
  40. //prefix[block c's end] - prefix[block c's begin - 1]
  41. ycnt += (prfc[c * y + y - 1] - prfc[c * y - 1]) * c;
  42. }
  43. // first the situation that both x in one wood
  44. int p = -1;
  45. for (int c = _max / y + 1; ~c; --c){
  46. // the start position and the end position of current block(c)
  47. int blk_sp = c * y, blk_ep = c * y + y - 1;
  48. if (l1[blk_ep] >= blk_sp && (p == -1 || p % y < l1[blk_ep] % y))
  49. p = l1[blk_ep];
  50. if (~p)
  51. flush((c * y + p % y) >> 1, ycnt - c, y);
  52. }
  53. // second the situation that each x in one different wood
  54. int p1 = -1, p2 = -1;
  55. for(int c = _max / y + 1; ~c; --c){
  56. // the start position and the end position of current block(c)
  57. int blk_sp = c * y, blk_ep = c * y + y - 1;
  58. if(~p2){
  59. //situation 1 - now both p1 and p2 is behind c
  60. flush(c * y + p1 % y, ycnt - c * 2 - 1, y);
  61. flush(c * y + p2 % y, ycnt - c * 2, y);
  62. }
  63. if (~p1 && l1[blk_ep] >= blk_sp && l1[blk_ep] % y > p2 % y){
  64. if (l1[blk_ep] % y >= p1 % y){
  65. //situation 3 - p1 is in c, p2 is behind c
  66. flush(c * y + p1 % y, ycnt - c * 2, y),
  67. flush(l1[blk_ep], ycnt - c * 2 - 1, y);
  68. }
  69. else{
  70. //situation 4 - p1 is behind c, p2 is in c
  71. flush(l1[blk_ep], ycnt - c * 2, y);
  72. }
  73. }
  74. //update
  75. if (l1[blk_ep] >= blk_sp && p2 % y < l1[blk_ep] % y)
  76. p2 = l1[blk_ep];
  77. if (p1 % y < p2 % y) swap(p1, p2);
  78. if (l2[blk_ep] >= blk_sp && p2 % y < l2[blk_ep] % y)
  79. p2 = l2[blk_ep];
  80. if (p1 % y < p2 % y) swap(p1, p2);
  81. if (~p2){
  82. //situation 2 - p1, p2 is both behind c
  83. //* if (p1, p2) isn't both in c, it's useless but won't cause WA
  84. flush(c * y + p2 % y, ycnt - c * 2, y);
  85. }
  86. }
  87. }
  88. printf("%I64d", ans);
  89. return 0;
  90. }

[CF1223G/1240E]Wooden Raft 题解的更多相关文章

  1. HDU 1051 Wooden Sticks 贪心题解

    本题一看就知道是最长不减序列了,一想就以为是使用dp攻克了. 只是那是个错误的思路. 我就动了半天没动出来.然后看了看别人是能够使用dp的,只是那个比較难证明其正确性,而其速度也不快.故此并非非常好的 ...

  2. UVALive 7276 Wooden Signs (DP)

    Wooden Signs 题目链接: http://acm.hust.edu.cn/vjudge/contest/127406#problem/E Description http://7xjob4. ...

  3. HDU1051 Wooden Sticks 【贪婪】

    Wooden Sticks Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) To ...

  4. Wooden Sticks -HZNU寒假集训

    Wooden Sticks There is a pile of n wooden sticks. The length and weight of each stick are known in a ...

  5. HDU 1005 Wooden Sticks

    http://acm.hdu.edu.cn/showproblem.php?pid=1051 Problem Description There is a pile of n wooden stick ...

  6. HDU-1051/POJ-1065 Wooden sticks 木棍子(动态规划 LIS 线型动归)

    嘤嘤嘤,实习半年多的小蒟蒻的第一篇博客(题解) 英文的: There is a pile of n wooden sticks. The length and weight of each stick ...

  7. 分布式系统理论进阶 - Raft、Zab

    引言 <分布式系统理论进阶 - Paxos>介绍了一致性协议Paxos,今天我们来学习另外两个常见的一致性协议——Raft和Zab.通过与Paxos对比,了解Raft和Zab的核心思想.加 ...

  8. 分布式一致性算法--Raft

    前面一篇文章讲了Paxos协议,这篇文章讲它的姊妹篇Raft协议,相对于Paxos协议,Raft协议更为简单,也更容易工程实现.有关Raft协议和工程实现可以参考这个链接https://raft.gi ...

  9. 2016 华南师大ACM校赛 SCNUCPC 非官方题解

    我要举报本次校赛出题人的消极出题!!! 官方题解请戳:http://3.scnuacm2015.sinaapp.com/?p=89(其实就是一堆代码没有题解) A. 树链剖分数据结构板题 题目大意:我 ...

随机推荐

  1. kafka整理笔记笔记

    一.为什么需要消息系统 解耦: 允许你独立的扩展或修改两边的处理过程,只要确保它们遵守同样的接口约束. 冗余: 消息队列把数据进行持久化直到它们已经被完全处理,通过这一方式规避了数据丢失风险.许多消息 ...

  2. Dedesql数据库类详解(二次开发必备教程)

    其实数据库类织梦之前就有一个介绍,http://help.dedecms.com/v53/archives/functions/db/,这篇文章讲解了数据库类的一些常见的使用方法,不过没有结合例子去介 ...

  3. 02:linux常用命令

    1.1 linux查看系统基本参数常用命令 1.查看磁盘 [root@linux-node1 ~]# df -hl Filesystem Size Used Avail Use% Mounted on ...

  4. 实现Promise类

    基本使用: let promise = new Promise((resolve, reject) => { // do something if (true) { resolve('succe ...

  5. Intel Coleto Creek SSL chipset

    Intel Coleto Creek SSL chipset name type interface speed model SR-IOV driver Intel SSL chipset Colet ...

  6. python的加密方式

    MD5加密 这是一种使用非常广泛的加密方式,不可逆的,在日常字符串加密中经常会用到,下面我简单介绍一下这种方式,主要用到Python自带的模块hashlib,测试代码如下,先创建一个md5对象,然后直 ...

  7. python 安装时,为何pip install不是内部或者外部命令错误解决办法

    新安装的python 环境,第一次pip  install 却报不是内部或者外部命令错误 首先检查一下环境变量,可能时你没有设置环境变量 再说一遍,安装python环境时,记得出了python.exe ...

  8. python 读excel表操作

    import xlrd # 打开文件 data = xlrd.open_workbook('测试表.xlsx') # 查看工作表 data.sheet_names() print("shee ...

  9. sftp及两种连接模式简介

    sftp是ssh内含的协议,只要sshd服务器启动了,它就可用,它本身不需要ftp服务器启动. FTP服务器和客户端要进行文件传输,就需要通过端口来进行.FTP协议需要的端口一般包括两种: 控制链路- ...

  10. windows删除已注册服务

    背景:近日,想要学习mysql主从复制,于是想在本地用多个mysql实例进行试验,试验的过程中总是挫折不断,生手不易,安装了很多实例,测试完成之后,想要删除这些实例. 虽然任务管理器可以停止任务,但是 ...