hihocoeder1384

算法竞赛进阶指南上的题目

我们肯定是吧最大值和最小值匹配,次大值和次小值匹配以此类推

首先,类似于区间覆盖的思想,我们对于一个\(L\),找到最大的满足条件的\(R\)

之后把\(R + 1\)作为下一个\(L\)继续这个操作

现在,问题转化成了我们如何寻找最大的\(R\)

一个比较明显的思路就是去二分,但是二分时间复杂度不对

因为如果每次只能前进一格,二分时间复杂度就变成了\(n^2\log{n}\)

考虑倍增的思想

我们对于每个\(L\)

初始设置\(R= L - 1,p = 1\)

之后求加上\([R + 1,R + p]\)时候合法

合法的话 \(p = p \times 2\)

否则 \(p = p / 2\)

每次暴力判断新加入的区间是否合法

可以证明这样时间复杂度

为\(n\log^2{n}\)

之后发现,对于新加进来的区间,我们只需要把它排序,然后和原有的区间进行归并即可

时间复杂度就变成了\(n\log n\)

  1. #include<cstdio>
  2. #include<iostream>
  3. #include<queue>
  4. #include<algorithm>
  5. #include<cstring>
  6. #include<cctype>
  7. #include<vector>
  8. #include<ctime>
  9. #include<cmath>
  10. #define LL long long
  11. #define pii pair<int,int>
  12. #define mk make_pair
  13. #define fi first
  14. #define se second
  15. #define min std::min
  16. #define max std::max
  17. const int N = 5e5 + 3;
  18. int a[N];
  19. int n,m;LL k;
  20. std::vector <int> A,B,G;
  21. inline LL read(){
  22. LL v = 0,c = 1;char ch = getchar();
  23. while(!isdigit(ch)){
  24. if(ch == '-') c = -1;
  25. ch = getchar();
  26. }
  27. while(isdigit(ch)){
  28. v = v * 10 + ch - 48;
  29. ch = getchar();
  30. }
  31. return v * c;
  32. }
  33. inline bool check(int l,int r){
  34. B.clear(),G.clear();
  35. for(int i = l;i <= r;++i) B.push_back(a[i]);
  36. sort(B.begin(),B.end());
  37. int now1 = 0;int now2 = 0;
  38. while(now1 < A.size() && now2 < B.size()){
  39. if(A[now1] < B[now2]) G.push_back(A[now1++]);
  40. else G.push_back(B[now2++]);
  41. }
  42. while(now1 < A.size()) G.push_back(A[now1++]);
  43. while(now2 < B.size()) G.push_back(B[now2++]);
  44. LL res = 0;
  45. now1 = 0,now2 = G.size() - 1;
  46. for(int cnt = 0;cnt < m && now1 < now2;now1++,now2--,cnt++) res += 1ll * (G[now1] - G[now2]) * (G[now1] - G[now2]);
  47. if(res <= k){
  48. A = G;
  49. return 1;
  50. }
  51. else return 0;
  52. }
  53. int main(){
  54. // freopen("A.in","r",stdin);
  55. // freopen("A1.out","w",stdout);
  56. int T = read();
  57. while(T--){
  58. int ans = 0;
  59. n = read(),m = read(),k = read();
  60. for(int i = 1;i <= n;++i) a[i] = read();
  61. int l = 1,r = 0;
  62. while(l <= n){
  63. int p = 1;
  64. A.clear();
  65. while(p){
  66. int t = min(n,r + p);
  67. if(check(r + 1,t)){
  68. r = t;
  69. if(t == n) break;
  70. p <<= 1;
  71. }
  72. else p >>= 1;
  73. }
  74. l = r + 1;
  75. ans++;
  76. }
  77. printf("%d\n",ans);
  78. }
  79. return 0;
  80. }
  81. /*
  82. 1
  83. 10 2 10
  84. 4 1 3 2 1 3 2 1 3 4
  85. */

hihocoeder1384的更多相关文章

随机推荐

  1. sql表连接 —— join

    一.内连接 —— INNER JOIN 内连接是最常见的一种连接,只连接匹配的行. 表1: 表2: 执行查询: select StudentId as 学生编号,StudentName as 姓名,G ...

  2. 2017 ACM-ICPC 亚洲区(南宁赛区)网络赛 M. Frequent Subsets Problem【状态压缩】

    2017 ACM-ICPC 亚洲区(南宁赛区)网络赛  M. Frequent Subsets Problem 题意:给定N和α还有M个U={1,2,3,...N}的子集,求子集X个数,X满足:X是U ...

  3. mysql带有子查询的like查询

    SELECT * FROM by_app_categories WHERE c_name LIKE CONCAT('%', (SELECT `name` FROM b_catelist WHERE t ...

  4. 中断源记录 INT0 INT1

    中断源记录 INT0 INT1 用到一个单片机 使用的 P3.1 P3.3 作为唤醒口,后来发一 P3.1 和 P3.3 使用的同一个中断 INT1,这个尴尬了,只能两选 一. 查看规格书,还好 P3 ...

  5. gcc需找头文件路径

    `gcc -print-prog-name=cc1plus` -v This command asks gcc which C++ preprocessor it is using, and then ...

  6. 洛谷P1060 开心的金明

    //01背包 价值等于重要度乘体积 #include<bits/stdc++.h> using namespace std; ; ; int n,m,v[maxn],w[maxn],f[m ...

  7. @atcoder - Japanese Student Championship 2019 Qualification - E@ Card Collector

    目录 @description@ @solution@ @accepted code@ @details@ @description@ N 个卡片放在 H*W 的方格图上,第 i 张卡片的权值为 Ai ...

  8. laravel 5.5 登录验证码 captcha 引入

    https://blog.csdn.net/u013372487/article/details/79461730 前提: 开启Laravel 的用户认证功能 1.安装 Captcha 安装 Capt ...

  9. C++第5次作业

    运算符重载 定义 - 运算符重载是对已有的运算符赋予多重含义,使同一个运算符作用于不同类型的数据时导致不同行为. 运算符重载规则 - C++运算符除了少数几个,全都可以重载,且只能重载C++已有的运算 ...

  10. poj 1039 Pipe (Geometry)

    1039 -- Pipe 理解错题意一个晚上._(:з」∠)_ 题意很容易看懂,就是要求你求出从外面射进一根管子的射线,最远可以射到哪里. 正解的做法是,选择上点和下点各一个,然后对于每个折点位置竖直 ...