\(\\\)

\(Description\)


对一长为\(N\)的数列\(A\)排序,不保证数列元素互异:

  • 数列\(A\)中\(A[1...i]\)的最大值不大于\(A[i+1…N]\)的最小值,我们就称元素\(i\)和\(i+1\)之间的位置为一个分隔点.

  • 当数列未排好序时,将每一个由分隔点分出的区间单独进行一次顺序扫描的冒泡排序,循环至数列排好序。

  • 形式化的代码可以描述成:

    work_counter = 0
    bubble_sort_pass (A) {
    for i = 0 to length(A)-2
    if A[i] > A[i+1], swap A[i] and A[i+1]
    }
    quickish_sort (A) {
    if length(A) = 1, return
    do {
    work_counter = work_counter + length(A)
    bubble_sort_pass(A)
    } while (no partition points exist in A)
    divide A at all partition points;
    recursively quickish_sort each piece
    }

求退出循环后\(work\_counter\)的值。

  • \(N\in [0,10^5]\),\(A_i\in [0,10^9]\)

\(\\\)

\(Solution\)


  • 注意到由定义的分隔点分开的每一个区间内,所有元素只会在这一区间内交换,而不会越过分隔点,所以对每一个区间单独冒泡排序与对整个数列冒泡排序是一样的。

  • 所以问题中计数的递归区间总长度,其实是每一个数字被比较的次数之和,其实就是每个数字被递归的层数之和。当一个数字不再被递归计算,当且仅当区间长度为\(1\),即左右都产生了分隔点。于是问题变为:计算每一个数左右都产生分隔点所需的递归次数之和。

  • 每一个数左右都产生分隔点的递归次数又可以看做两个分隔点产生的时间取\(max\),于是只需统计每一个分隔点产生的递归层数。

  • 回到分隔点定义,一个分割点产生,只需要两侧的元素都正确的分开,而不是两侧都排好序。所以一个分隔点产生的时间,是所有应该在左区间的右区间的数移到左区间的时间,和所有应该在右区间的左区间的数移到右区间的时间取最大值。注意到是单向冒泡排序,所以排序的瓶颈在于应当向前移动的那些数字,因为它们每次只会向前移动一个位置。所以我们需要统计离分隔点最远的应移到左区间的点,到分隔点的距离。

  • 于是排序后第一遍扫描统计每一个分隔点产生时间,第二遍扫描累加答案即可。要注意即使一个元素开始就在应该在的地方,即左右分隔点产生时间都为\(0\),也应该计数,因为运行代码中,开始需要将数列扫描一遍来确定是否需要递归。

\(\\\)

\(Code\)


#include<cmath>
#include<cstdio>
#include<cctype>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 100010
#define R register
#define gc getchar
using namespace std;
typedef long long ll; inline ll rd(){
ll x=0; bool f=0; char c=gc();
while(!isdigit(c)){if(c=='-')f=1;c=gc();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=gc();}
return f?-x:x;
} ll n,ans=1,t[N];
struct seq{ll x,p;}s[N]; inline bool cmp(seq x,seq y){
return x.x==y.x?x.p<y.p:x.x<y.x;
} int main(){
n=rd();
if(n==0){puts("0");return 0;}
for(R ll i=1;i<=n;++i){s[i].x=rd();s[i].p=i;}
sort(s+1,s+1+n,cmp);
for(R ll i=1,mx=0;i<=n;++i){
mx=max(mx,s[i].p); t[i]=mx-i;
}
ans=t[1];
for(R ll i=2;i<=n;++i) ans+=max(t[i-1],max(t[i],1ll));
printf("%lld\n",max(ans,n));
return 0;
}

最新文章

  1. Leetcode Valid Number
  2. JSP中动态INCLUDE与静态INCLUDE的区别
  3. python日期格式化与绘图
  4. Ubuntu 12 修改环境变量
  5. 我的c++学习(2)比较两个数字大小
  6. deleteRow
  7. VS~单步调试DLL
  8. 内核加载与linux的grub
  9. 14.2.5.4 Physical Structure of an InnoDB Index InnoDB Index 的物理结构
  10. 【Struts2学习笔记(11)】对action的输入校验和XML配置方式实现对action的全部方法进行输入校验
  11. ios导航栏又按钮添加图片后使其保持原色
  12. 【Visual C++】游戏编程学习笔记之六:多背景循环动画
  13. 学习Identity Server 4的预备知识 (误删, 重补)
  14. HP-Socket v5.0.1:支持 IPv6 及多 SSL 证书
  15. html、css基础整理
  16. python基础之Day11
  17. Emergency(山东省第一届ACM程序设计真题+Floyd算法变型)
  18. Ubuntu读取/root/.profile时发现错误:mesg:ttyname fa
  19. CKEDITOR的内容js转码,C#控制器解码接收
  20. Sizzle源码分析:二 词法分析

热门文章

  1. 判断项目中是否有slf4j的实现类
  2. Linux学习总结(18)——Linux使用init命令关机、重启、切换模式
  3. Leetcode 92.反转链表
  4. [luoguP1373] 小a和uim之大逃离(DP)
  5. CF558E A simple task 线段树
  6. 二叉堆练习3&amp;【模板】堆
  7. tyvj1271 零式求和
  8. zoj——3557 How Many Sets II
  9. Memcached的Web管理工具MemAdmin(待实践)
  10. 【CV论文阅读】:Rich feature hierarchies for accurate object detection and semantic segmentation