• (模拟)HDU


    原题链接:

    http://acm.split.hdu.edu.cn/showproblem.php?pid=5857

    (可能会失效)


    题意:

    给你一个升序的数列,查询两个区间合并之后的数列里的中位数


    分析:

    看到100000,就会以为是线段树。其实显然没有充分利用已经升序这个特性,仔细考虑其实就是一道模拟题。

    乍一看,会有三种情况:

    1、两段区间分离

    2、两段区间相交

    3、一段区间包含另一段区间

    (然后还会突然想到,两个区间以一定是前后再前,细思恐极,可怕的模拟题)

    其实很多情况可以通过一定的合并变成另一种状态:

    1、两区间先后在前,可以通过左端点互换和右端点互换,变成先前再后。

    2、区间包含可以通过右端点互换,使之变为区间相交。

    最终得出结论,只有两种情况:分离和相交。

    还有一些注意的是合并之后新数列的长度的奇偶,因为怕出错,所以直接分类讨论,没有做过多的转化和代码缩减、

    在区间相交的情况下,会产生3段区间,中间的区间是重复区间

    在重复区间中,必然存在两个两个连在一起吗,所以只要

    在相交的情况下,中间一段因为是重复的。只需要先求出在重复区间去重的情况下是第几个就行了,

    然后除以2,向上取整。


    代码:

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cmath>
     4 #include <algorithm>
     5 
     6 using namespace std;
     7 
     8 const int maxn=100010;
     9 long long num[maxn];
    10 
    11 int main() {
    12     int t;
    13     scanf("%d",&t);
    14     while(t--) {
    15         int n,m;
    16         scanf("%d%d",&n,&m);
    17         for(int i=1; i<=n; i++) {
    18             scanf("%I64d",&num[i]);
    19         }
    20         for(int i=0; i<m; i++) {
    21             double ans=0;
    22             int l1,r1,l2,r2;
    23             scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
    24             if(l1>l2||(l1==l2&&r1>r2)) {
    25                 swap(l1,l2);
    26                 swap(r1,r2);
    27             }
    28             if(l1<=l2&&r1>=r2) {
    29                 swap(r1,r2);//区间包含转化为区间相交
    30             }
    31             int len1=r1-l1+1;
    32             int len2=r2-l2+1;
    33             int len=len1+len2;
    34             if(r1<l2) {//两区间分离
    35                 if(len%2==0) {
    36                     int half=len/2;
    37                     if(len1>half) {
    38                         ans=double(num[l1+half-1]+num[l1+half])/2;
    39                     } else if(len2>half) {
    40                         ans=double(num[r2-half+1]+num[r2-half])/2;
    41                     } else if(len1==half) {
    42                         ans=double(num[r1]+num[l2])/2;
    43                     }
    44                 } else {
    45                     int half=len/2+1;
    46                     if(len1>=half) {
    47                         ans=double(num[l1+half-1]);
    48                     } else {
    49                         ans=double(num[r2-half+1]);
    50                     }
    51                 }
    52             } else {//两区间相交
    53                 if(len%2==0) {
    54                     int half=len/2;
    55                     if(l1+half-1<l2) {
    56                         ans=double(num[l1+half-1]+num[l1+half])/2;
    57                     } else if(r2-half+1>r1) {
    58                         ans=double(num[r2-half+1]+num[r2-half])/2;
    59                     } else {
    60                         half=half-(l2-l1);
    61                         ans=double(num[l2+(int)ceil(double(half)/2)-1]+num[l2+(int)ceil(double(half+1)/2)-1])/2;//
    62                     }
    63                 } else {
    64                     int half=len/2+1;
    65                     if(l1+half-1<l2) {
    66                         ans=double(num[l1+half-1]);
    67                     } else if(r2-half+1>r1) {
    68                         ans=double(num[r2-half+1]);
    69                     } else {
    70                         half=half-(l2-l1);
    71                         ans=double(num[l2+(int)ceil(double(half)/2)-1]);
    72                     }
    73                 }
    74             }
    75             printf("%.1f
    ",ans);
    76         }
    77     }
    78     return 0;
    79 }
  • 相关阅读:
    LeetCode 297. 二叉树的序列化与反序列化
    LeetCode 14. 最长公共前缀
    LeetCode 1300. 转变数组后最接近目标值的数组和
    bigo一面凉经
    LeetCode 128.最长连续序列
    LeetCode中二分查找算法的变种
    LeetCode 93. 复原IP地址
    LeetCode 1004. 最大连续1的个数 III
    LeetCode 1282. 用户分组
    多线程理解
  • 原文地址:https://www.cnblogs.com/tak-fate/p/5786246.html
Copyright © 2020-2023  润新知