zoukankan      html  css  js  c++  java
  • BZOJ 5277 IQ题orz

     思路:

    首先我们注意到,对一个序列按分割点分开以后分别冒泡其实就相当于对整个序列进行冒泡。每一个元素都会对复杂度贡献1,除非一个元素两边的分割点都出现了。因此我们可以完全忽略快排的递归过程。只需考虑每个元素在经历几趟冒泡排序之后两边的分割点都出现了。

    考虑一个分割点,不妨就是在i,i+1之间的这个分割点,他在几趟冒泡排序之后会出现呢?出现了这个分割点,说明前i小的元素都已经在前i个了,我们记前i小的元素一开始最大的下标为x,则在x-i趟冒泡之后就会把x挪到前i个位置(因为每趟冒泡一定会使x的下标-1)。也就是说i,i+1之间的分割点会在x-i趟冒泡之后出现。而第i个元素的贡献就是它左右分割点出现时间的最大值。

     from https://blog.csdn.net/Icefox_zhx/article/details/80025305

    注意如果有相同的数的时候,按照出现的position从小到大排序

    (这破题搞了一上午我真是退役选手了)

    //By SiriusRen
    #include <bits/stdc++.h>
    using namespace std;
    const int N=100050;
    int n,mx[N],cnt[N];long long ans;
    struct Nd{int w,p;}a[N];
    bool cmp(Nd a,Nd b){if(a.w!=b.w)return a.w<b.w;return a.p<b.p;}
    int main(){
        scanf("%d",&n);
        for(int i=1;i<=n;i++)scanf("%d",&a[i].w),a[i].p=i;
        sort(a+1,a+1+n,cmp);
        for(int i=1;i<n;i++)mx[i]=max(mx[i-1],a[i].p),cnt[i]=max(mx[i]-i,1);
        for(int i=1;i<=n;i++)ans+=max(cnt[i],cnt[i-1]);
        printf("%lld
    ",ans);
    }

     附一个暴力程序

    //By SiriusRen
    #include <bits/stdc++.h>
    using namespace std;
    const int N=200050,inf=0x3f3f3f3f;
    int n,a[N],work_counter,minn[N],maxx[N];
    void bubble_sort_pass(int *a,int len){
        for(int i=0;i<=len-2;i++)if(a[i]>a[i+1])swap(a[i],a[i+1]);
    }
    int get_partition_points(int *a,int len){
        minn[len]=inf;maxx[0]=a[0];int temp=0;
        for(int i=len-1;~i;i--)minn[i]=min(minn[i+1],a[i]);
        for(int i=1;i<len;i++)maxx[i]=max(maxx[i-1],a[i]);
        for(int i=0;i<len-1;i++)if(maxx[i]<=minn[i+1])temp++;
        return temp;
    }
    void quickish_sort(int *a,int len){
        if(len==1)return;
        work_counter+=len,bubble_sort_pass(a,len);
        minn[len]=inf;maxx[0]=a[0];int temp=0;
        for(int i=len-1;~i;i--)minn[i]=min(minn[i+1],a[i]);
        for(int i=1;i<len;i++)maxx[i]=max(maxx[i-1],a[i]);
        vector<int>v;
        for(int i=0;i<len-1;i++)if(maxx[i]<=minn[i+1])v.push_back(i);
        if(v.empty())return;
        quickish_sort(a,v[0]+1);
        for(int i=0;i<v.size()-1;i++)quickish_sort(a+v[i]+1,v[i+1]-v[i]);
        quickish_sort(a+v[v.size()-1]+1,len-v[v.size()-1]-1);
    }
    int main(){
        scanf("%d",&n);
        for(int i=0;i<n;i++)scanf("%d",&a[i]);
        quickish_sort(a,n);
        printf("%d
    ",work_counter);
    }
  • 相关阅读:
    matlab二维绘图学习摘要
    linux下有名管道进程通信
    《编写可读代码的艺术》第10章 抽取不相关的子问题
    《编写可读代码的艺术》第9章 变量可读性
    《编写可读代码的艺术》第8章 拆分超长的表达式
    《编写可读代码的艺术》第7章 简化循环和逻辑
    《编写可读代码的艺术》第6章 写出言简意赅的注释
    《编写可读代码的艺术》第5章 该写什么样的注释
    《编写可读代码的艺术》第4章 审美
    《编写可读代码的艺术》第3章 不会误解的名字
  • 原文地址:https://www.cnblogs.com/SiriusRen/p/9354069.html
Copyright © 2011-2022 走看看