提交地址。


关于lyd给的倍增方法,即从当前枚举向后的$2^k$长度($k$从$1$开始),如果可行就将$k$加一以扩大范围,不可行时将范围不断减半直至$0$。

举个例子,假设当下在1,目标答案是13,那么枚举的范围变化情况是$2$,$4$,$8$,$16$(不行,且范围开始缩小),$12$,$14$(不行),$13$,$13$(范围缩小至0)。

并没有看出这样倍增有什么好处。复杂度可证也是$O(logN)$的,但是不是会带个2左右的常数么。。具lyd所说,当目标答案位置较近时会加快效率。

但是这不影响整体复杂度啊。。带着不很理解的态度看了例题才明白这种倍增姿势相较于二分或者从大到小二倍增的优势所在。


题意:数列$N \leqslant 500000$,求划分最少区间使得每段区间任选$M$对数字(不重复选,不够$M$对的时候能选多少选多少)的差的平方之和小于$K$。


首先很容易证明(cai ce)到对于一列数的最大的上述价值就是将最大数减最小数平方加上次大数减次小数平方加上......也就是排序后头尾相配。可以微调法证明任意一种其他策略不会更优。此贪心为关键之一。

然后因为满足要求的一段区间显然越长越好,所以从起点开始拓展,拓展到最远的地方记下来,反复接替拓展,一定是最小区间数。又因为答案随数列增长是有单调性的,所以可以二分检查找到最远的符合要求的右端点。

每次check时候对区间进行排序,加上二分以及区间数的复杂度,最坏$O(N^2log^2N)$。

可以发现,二分时候每次排序都是一个$O(NlogN)$,因为最坏可能答案在比较靠右的位置。这个时候,lyd给出的倍增方案就派上用场了。


lyd书上描述的倍增方法,总是将复杂度限制在$log($答案区间的长度$)$。假若我们采用这种倍增,那么每次枚举的区间最长长度假设为$K$,则找到这样一个区间的复杂度是$O(Klog^2K)$。(倍增一个$logK$,每次排序一个$KlogK$)而不是原来完整的N。

那么,每个区间的复杂度累加起来不会超过$O(Nlog^2N)$。很容易证。所以通过限制枚举次数在答案对数内,累加起来就比原来少一个log。这就是这种倍增优势。


但是$O(Nlog^2N)$仍然过不了。考虑到每次都要排序,前面已经可行的区间又被拉进来排了一次,显然浪费时间。于是可以只对当前试探的这段区间排序后,和原来已排好序的两个数列归并。归并完求代价,判断是否满足要求。

每次只对新的一小段排序,总体累加起来每次拓展的排序复杂度是$O(KlogK)$的(对于枚举过头了的区间,虽然不断缩小不断重复排序,但由于每次的排序复杂度折半,总体不会超过原来大区间的两倍)。

而$logK$次倍增每次复制需要$O(K)$,所以也是$O(KlogK)$.

最后,总体累加,复杂度$O(NlogN)$。

这题给予我们几个启发:二分和倍增都可用于有单调性的查找,有时候两者没有什么区别,但有时的check函数复杂度和答案位置有关倍增可以通过限制此条件使得总体复杂度优化掉。


代码写起来的话还是很少的。

WA记录

  • line61智障没考虑边界。
  • line49笔误。。
  • line59每次初始值。。哎可能是我倍增没有操作好
  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<cmath>
  5. #include<algorithm>
  6. #include<queue>
  7. #define dbg(x) cerr<<#x<<" = "<<x<<endl
  8. #define _dbg(x,y) cerr<<#x<<" = "<<x<<" "<<#y<<" = "<<y<<endl
  9. using namespace std;
  10. typedef long long ll;
  11. template<typename T>inline char MIN(T&A,T B){return A>B?A=B,:;}
  12. template<typename T>inline char MAX(T&A,T B){return A<B?A=B,:;}
  13. template<typename T>inline T _min(T A,T B){return A<B?A:B;}
  14. template<typename T>inline T _max(T A,T B){return A>B?A:B;}
  15. namespace io{
  16. const int SIZE = ( << ) + ;
  17. char ibuf[SIZE], *iS, *iT, obuf[SIZE], *oS = obuf, *oT = oS + SIZE - , c, qu[]; int f, qr;
  18. #define gc() (iS == iT ? (iT = (iS = ibuf) + fread (ibuf, 1, SIZE, stdin), (iS == iT ? EOF : *iS ++)) : *iS ++)
  19. inline void flush (){fwrite (obuf, , oS - obuf, stdout);oS = obuf;}
  20. inline void putc (char x){*oS ++ = x;if (oS == oT) flush ();}
  21. template <class I>
  22. inline void read(I &x) {for (f = , c = gc(); c < '' || c > ''; c = gc()) if (c == '-') f = -;
  23. for (x = ; c <= '' && c >= ''; c = gc()) x = x * + (c & ); x *= f;}
  24. template <class I>
  25. inline void print (I x){
  26. if (!x) putc (''); if (x < ) putc ('-'), x = -x;while(x) qu[++ qr] = x % + '', x /= ;while (qr) putc (qu[qr--]);}
  27. struct Flusher_ {~Flusher_(){flush();}}io_flusher_;
  28. }
  29. using io::read;
  30. using io::putc;
  31. using io::print;
  32. const int N=+;
  33. int a[N],tmp[N],b[N],c[N];//c:临时排序数组 b:已归并好的数组 tmp:临时归并数组
  34. ll k;
  35. int T,n,m,ans;
  36.  
  37. inline void Merge(int L,int R,int r){
  38. int i=L,j=R+;
  39. for(register int k=L;k<=r;++k)
  40. if(b[i]<c[j]&&i<=R||j>r)tmp[k]=b[i++];
  41. else tmp[k]=c[j++];
  42. }
  43. inline ll calc(int L,int R,int r){
  44. if(r==R)return k+;//_dbg(L,R),dbg(r);
  45. for(register int i=R+;i<=r;++i)c[i]=a[i];
  46. sort(c+R+,c+r+);
  47. Merge(L,R,r);
  48. ll ret=;//for(register int i=L;i<=r;++i)printf("%d ",tmp[i]);puts("");
  49. for(register int i=L;i<=L+_min(m,(r-L+>>))-;++i)ret+=(tmp[r-i+L]-tmp[i])*1ll*(tmp[r-i+L]-tmp[i]);
  50. return ret;
  51. }
  52.  
  53. int main(){//freopen("test.in","r",stdin);//freopen("test.out","w",stdout);
  54. read(T);while(T--){
  55. read(n),read(m),read(k);
  56. for(register int i=;i<=n;++i)read(a[i]);
  57. ans=;int L=,R=,p,r;
  58. while(L<=n){
  59. p=;b[L]=a[L];
  60. while(p){
  61. if(calc(L,R,r=_min(n,R+p))<=k){
  62. for(register int i=L;i<=r;++i)b[i]=tmp[i];
  63. R=r,p<<=;
  64. }
  65. else p>>=;
  66. }
  67. L=R+,R=L,++ans;
  68. }
  69. print(ans);putc('\n');
  70. }
  71. return ;
  72. }

hihocoder1384/CH0601 Genius ACM[贪心+倍增+归并排序]的更多相关文章

  1. CH0601 Genius ACM【倍增】【归并排序】

    0601 Genius ACM 0x00「基本算法」例题 描述 给定一个整数 M,对于任意一个整数集合 S,定义“校验值”如下: 从集合 S 中取出 M 对数(即 2∗M 个数,不能重复使用集合中的数 ...

  2. $CH0601\ Genius\ ACM$ 倍增优化DP

    ACWing Description 给定一个长度为N的数列A以及一个整数T.我们要把A分成若干段,使得每一段的'校验值'都不超过N.求最少需要分成几段. Sol 首先是校验值的求法: 要使得'每对数 ...

  3. ACM-ICPC Beijing 2016 Genius ACM(倍增+二分)

    描述 给定一个整数 M,对于任意一个整数集合 S,定义“校验值”如下: 从集合 S 中取出 M 对数(即 2∗M 个数,不能重复使用集合中的数,如果 S 中的整 数不够 M 对,则取到不能取为止),使 ...

  4. AcWing:109. 天才ACM(倍增 + 归并排序)

    给定一个整数 MM,对于任意一个整数集合 SS,定义“校验值”如下: 从集合 SS 中取出 MM 对数(即 2∗M2∗M 个数,不能重复使用集合中的数,如果 SS 中的整数不够 MM 对,则取到不能取 ...

  5. hihocoder--1384 -- Genius ACM (倍增 归并)

    题目链接 1384 -- Genius ACM 给定一个整数 m,对于任意一个整数集合 S,定义“校验值”如下:从集合 S 中取出 m 对数(即 2*M 个数,不能重复使用集合中的数,如果 S 中的整 ...

  6. Contest Hunter 0601 Genius ACM

    Genius ACM Advanced CPU Manufacturer (ACM) is one of the best CPU manufacturer in the world. Every d ...

  7. [hihocoder #1384] Genius ACM 解题报告(倍增)

    题目链接:http://hihocoder.com/problemset/problem/1384 题目大意: 给定一个整数 M,对于任意一个整数集合 S,定义“校验值”如下: 从集合 S 中取出 M ...

  8. hihoCoder#1384 : Genius ACM

    对于一个固定的区间$[l,r]$,显然只要将里面的数字从小到大排序后将最小的$m$个和最大的$m$个配对即可. 如果固定左端点,那么随着右端点的右移,$SPD$值单调不降,所以尽量把右端点往右移,贪心 ...

  9. Codeforces 980E The Number Games 贪心 倍增表

    原文链接https://www.cnblogs.com/zhouzhendong/p/9074226.html 题目传送门 - Codeforces 980E 题意 $\rm Codeforces$ ...

随机推荐

  1. mybatis-generator自动生成代码时,只生成insert方法

    今天使用mybatis-generator自动生成代码时,发现只能生成insert方法, 以前所有的方法都是可以生成的,查看网上解决办法和检查数据库表结构后, 发现2种可以解决的办法: 1.修改myb ...

  2. python基础之编码

    ascci:字母.数字.特色字符,1个字节-8位Unicode:两个字节-16位,升级版四个字节-32位uft-8:最少一个字节-8位,英文字母-1个字节-8位,欧洲-2个字节-16位,中文-3个字节 ...

  3. 解析之Nginx解析

  4. vue 导出JSON数据为Excel

    1. 安装三个依赖 npm install file-saver --save npm install xlsx --save npm install script-loader --save-dev ...

  5. finereport 通过条件弹出 alert进行提示

    function convertDateFromString(dateString) { if (dateString) { var date = new Date(dateString.replac ...

  6. LINQ查询表达式详解(1)——基本语法、使用扩展方法和Lambda表达式简化LINQ查询

    简介 使用线程的主要原因:应用程序中一些操作需要消耗一定的时间,比如对文件.数据库.网络的访问等等,而我们不希望用户一直等待到操作结束,而是在此同时可以进行一些其他的操作.  这就可以使用线程来实现. ...

  7. sqlalchemy的常用字段

    #encoding: utf-8 from sqlalchemy import create_engine,Column,Integer,String,\ Float,Boolean,DECIMAL, ...

  8. 如何在Windows中手动生成SSH密钥?(转)

    在Windows上,您可以通过多种方式创建SSH密钥.Windows需要SSH客户端,但在其操作系统上没有默认的SSH客户端.请注意,Windows目前正在测试本机OpenSSH应用程序,一般,不提倡 ...

  9. ASP.NET Core WebApi使用Swagger生成API说明文档【xml注释版】

    ⒈新建ASP.NET Core WebAPi项目 ⒉添加 NuGet 包 Install-Package Swashbuckle.AspNetCore ⒊Startup中配置 using System ...

  10. thinkphp6下无法获取header头中的Authorization(apache版)

    今天遇到在thinkphp框架中获取不到header头里边的 Authorization ,后来在.htaccess里面加多一项解决,记录下: <IfModule mod_rewrite.c&g ...