\(\\\)

\(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;
}

[ USACO 2018 OPEN ] Out of Sorts (Platinum)的更多相关文章

  1. [ USACO 2018 OPEN ] Out of Sorts (Gold)

    \(\\\) \(Description\) 运行以下代码对一长为\(N\)的数列\(A\)排序,不保证数列元素互异: cnt = 0 sorted = false while (not sorted ...

  2. [ USACO 2018 OPEN ] Out of Sorts (Silver)

    \(\\\) \(Description\) 运行以下代码对一长为\(N\)的数列\(A\)排序,不保证数列元素互异: cnt = 0 sorted = false while (not sorted ...

  3. 【二分+拓扑排序】Milking Order @USACO 2018 US Open Contest, Gold/upc_exam_6348

    目录 Milking Order @USACO 2018 US Open Contest, Gold/upc_exam_6348 PROBLEM 题目描述 输入 输出 样例输入 样例输出 提示 MEA ...

  4. [USACO 2018 Open Contest]作业总结

    t1-Out of Sorts 题目大意 将最大的数冒泡排序到最后需要多少次操作. 分析 排序后判断距离. ac代码 #include<bits/stdc++.h> #define N 1 ...

  5. [USACO 2018 Feb Gold] Tutorial

    Link: USACO 2018 Feb Gold 传送门 A: $dp[i][j][k]$表示前$i$个中有$j$个0且末位为$k$的最优解 状态数$O(n^3)$ #include <bit ...

  6. [USACO 2018 Jan Gold] Tutorial

    Link: USACO 2018 Jan Gold 传送门 A: 对于不同的$k$,发现限制就是小于$k$的边不能走 那么此时的答案就是由大于等于$k$的边形成的图中$v$所在的连通块除去$v$的大小 ...

  7. [LOJ#2386]. 「USACO 2018.01 Platinum」Cow at Large[点分治]

    题意 题目链接 分析 假设当前的根为 rt ,我们能够在奶牛到达 \(u\) 之时拦住它,当且仅当到叶子节点到 \(u\) 的最短距离 \(mn_u \le dis_u\) .容易发现,合法的区域是许 ...

  8. 【杂题1】USACO 2018 Open Contest-练习

    https://www.xoj.red/contests/show/1231 下面会写一些题目的解析什么的,当然不会粘贴题目只是简单提一下 (部分题目简单的题目就不概括了) 其实难度应该前面比较低. ...

  9. [USACO 2018 December Contest]作业总结

    t1 Convention 题目大意 每一头牛都有一个来的时间,一共有\(n\)辆车,求出等待时间最长的那头牛等待的最小时间. 解法 第一眼看到这道题还以为是\(2018noip\)普及组的t3魔鬼题 ...

随机推荐

  1. RabbitMQ-高级特性(六)

    存储机制 待... 消息结构 惰性队列 惰性队列会尽可能将消息存入到磁盘中,消费者消费相应的消息才会加载到内存,它可以支持更长的队列 默认情况下生产者消息会尽可能存储到内存中就算设置持久化消息 也会再 ...

  2. [luoguP3252] [JLOI2012]树(DP)

    传送门 树上前缀和. 在树上找一条权值和为 s 的链,其中这个链上的点按深度递增(递减)(不同) dfs 每搜到一个点求它的前缀和 sum[x],放入 set 中. 在 set 中找 sum[x] - ...

  3. Win32编程API 基础篇 -- 5.使用资源

    使用资源 你可能想参考教程结尾的附近,为了获得跟VC++和BC++资源相关的信息. 在我们讲得更加深入之前,我将大致讲解一下资源的主题,这样在每个小节中我就不必再去重讲一遍了.在这一小节中,你不需要编 ...

  4. Java的动态代理(DynamicProxy)

    代理的概述 代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问.代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理. 代理模式UML图 ...

  5. Java设计模式补充:回调模式、事件监听器模式、观察者模式(转)

    一.回调函数 为什么首先会讲回调函数呢?因为这个是理解监听器.观察者模式的关键. 什么是回调函数 所谓的回调,用于回调的函数. 回调函数只是一个功能片段,由用户按照回调函数调用约定来实现的一个函数. ...

  6. 跳過 Windows RT的UI

    RT启动进入常规桌面 微软Surface RT发布的时间已经不短了,相信很多朋友都已经熟悉了这个全新的平板,并且已经上手.Surface RT开机默认进入的界面为Windows UI,这对于经常使用A ...

  7. [Vue @Component] Simplify Vue Components with vue-class-component

    While traditional Vue components require a data function which returns an object and a method object ...

  8. C++ Sleep Function 使用方法 Sleep(-1)

    <span style="font-size:18px;">//==================================================== ...

  9. 鸟哥的Linux私房菜-----10、学习Bash

  10. 2015南阳CCPC C - The Battle of Chibi DP树状数组优化

    C - The Battle of Chibi Description Cao Cao made up a big army and was going to invade the whole Sou ...