【排序优化】牛客练习赛54D

 

 

牛客练习赛54D

题目暴力做法是:

在m(m<=100)次循环内 分别对当前长度为n(n<=5e5)的数组sort一遍,大致取前k小(k<=100)。

我能想到的觉得比较优的做法是:在m次循环内,遍历数据并把符合大小的数据放进单调队列,保证单调队列的数据个数<=k,然后,不断判断新元素与队头元素的大小,更新答案。然而还是超时。

比赛题解是这么说的:

  作者:Sovietqwq✨

  链接:https://ac.nowcoder.com/discuss/342616?type=101&order=0&pos=1&page=1

  来源:牛客网
  对于当前区间l,rl,rl,r,随机选取一个元素costi​, i∈[l,r]作为基准数base。然后维护两个指针,将区间中所有小于base的元素放到base的左边,大于base的元素放到base右边。这一步可以O(区间长度)完成。
设结束时两个指针(即base)在p位置。p左边元素都小于base,p右边的元素都大于base(可能等于,不影响答案)。那么我们统计p左边的元素个数t,如果t≥k就递归到区间[l,p];否则答案加上p左边的所有花费,k-=t,递归到区间[p+1,r]。
复杂度为T(n)=T(2n​)+O(n)=O(n)。总复杂度O(nm)。

 

然后,这么做就不超时了!....

 

 

然后,还学习了一个东西:

可以很大随机数。

std::random_device rd;
std::mt19937 mt(rd());//或者直接:std::mt19937 mt(time(0));
int main()
{
    int a=mt()%mod;
    printf("%d",a);
}

 

2019-11-16


 

 

补充一点:

今天数据结构讲了“一趟快速排序”,它的改进版本,恰好就是这道题的类似做法。

 

取base为a[mid],base值左边的元素都比base小,base右边的元素值都比base大:

int a[maxn];
void one_qsort(int l,int r)
{
    int mid=(l+r)>>1;
    int base=a[mid];
    swap(a[l],a[mid]);
    while(l<r)
    {
        while(l<r&&a[r]>=base)r--;
        swap(a[l],a[r]);
        while(l<r&&a[l]<=base)l++;
        swap(a[l],a[r]);
    }
}

 

 

但这样子在这道题会超时,这道题排序的base是取随机id=mt()%(r-l)+l;

int id=mt()%(r-l)+l; base=a[id];

然后其他一样:

random_device rd;
mt19937 mt(rd());
int a[maxn];
void one_qsort(int l,int r)
{
    int id=mt()%(r-l)+l;
    int base=a[id];
    swap(a[l],a[id]);
    while(l<r)
    {
        while(l<r&&a[r]>=base)r--;
        swap(a[l],a[r]);
        while(l<r&&a[l]<=base)l++;
        swap(a[l],a[r]);
    }
}

 

2019-11-21


 

 

 

posted @ 2019-11-16 14:11  草丛怪  阅读(150)  评论(0编辑  收藏  举报