·大米兔学习全排列,还有一些逆序对,还有一棵二叉索引树。·

·分析:

      首先肯定不是像题目上说的那样,使用next_permutation去完成这道题,因为就算是线性的它也不能承受庞大的排列组合个数。

      我们发现这道题可以理解为:建造一个字典序尽量小的序列,满足:①字典序大于原序列②逆序数等于原数列。

      怎样才能满足字典序最小呢?首先,我们视作从原数列去修改得到我们的美妙新序列。为了使得新序列字典序尽量靠近原序列(这样才是答案),我们更愿意去修改靠近尾部的部分,这样字典序变换较小。如图:

转换一种思想:我们将要改变原序列的部分规定为原序列的一个后缀,也就是说啊,在这之前的部分我们不作更改,并且改变后这一段的逆序对数目不发生改变。如图啦啦:

     那么为什么修改段尽量靠后就一定是答案呢?因为如果靠前一点,如果后面段已经存在解了,那么较长的后缀里构造出来的数列的字典序一定大于等于较短一段。因此,我们需要寻找满足条件的最短后缀,找到以后,对调整它内部元素的顺序,构成答案。

     照此思路,必有两个步骤:①找到这个后缀是谁(代码中可以体现为找到后缀左端点)②调整这个区间内的元素顺序,构造答案。

     (1)寻找那个梦中的后缀:

      不是所有的短后缀都能通过仅修改它内部的元素构造最终答案。我们观赏以下情况,为了方便理解;

      我们用柱柱的高度表示每个元素的大小,红色部分表示我们选择这一段后缀来修改,设i为后缀的左端点下标,使用now表示当前数i在区间[i,n]的逆序对数(也就是在这个后缀中关于i的逆序对个数),使用sum表示这个后缀中的总逆序对数[一句提醒:i之前的逆序对我们是不会理睬它的]。我们在草稿纸上乱涂乱画,轻松发现下列情况是不合法的(即仅选择这一段后缀进行修改是不能达到目的的):

【1】单调上升型:

由于后缀区间里的逆序对个数为0,所以我们不可能仅通过调整红色部分内部的元素顺序来保持原来的逆序对总数。这种情况的判断方式为:sum==0。

【2】单调递减型

这种情况的不合法的原因和上文类似。由于逆序对数已经达到了这个区间的唯一最大值:(n-i)*(n-i+1),不可能有其他排列方式。这种情况的判断方式为:sum==(n-i)*(n-i+1)。

【3】垄断型:

此时后缀区间内的所有逆序对都是与i相关的,即sum==now。由于我们要构造字典序更大的一个后缀,那么只能把i位置放上比a[i]大的元素(例如图中的最后一个元素),这个元素一放过来,那么必定会至少造成now+1个逆序对(就是原来i的逆序对和它与i组成的逆序对)。

     上文几个自然段已经列出了判断条件,这让我们可以快乐而顺利地从右向左找到第一个合法的后缀i。接下来就要努力构造答案了。

(2)在那个后缀中建造我们的梦:

     对于第I位(也就是这个后缀区间的左端点),我们需要保证这一位要换成一个比原来的a[i]大的,但值又尽量小的元素。我们有i的now值可以得到:

在这个后缀区间中,i是第(now+1)小,所以我们为保证新序列字典序尽量小,把i位替换成这个序列第(now+2)大的数(注意,不是整个序列第几大,是这个后缀中的第几大,怎么找到它呢,一会儿说好吗?好)。其实接下来处理完i位后,我们依次处理i+1~n位的方法大体相同:

     方法为:我们要尽力使得这个序列字典序最小。啊?这是什么方法啊。欣赏下面这幅图:

我们要坚持让j位元素尽量小的原则(在这之前的部分已经填好数),要让这个数尽量小,也就是它的和剩余区间的逆序对要尽量少,那么在总逆序对保持不变的情况下(这是关键),那么就要使[j+1,n]内部的逆序对尽量多,我们考虑最极端情况,也就是[j+1,n]部分直接呈现单调递减型,那么这样逆序对最大,使得关于j的逆序对最小,使得j位的数最小。

     ①②整个过程思路如下:

      从右向左扫描,找到第一个通过修改能够构成满足条件的字典序最小的新序列的后缀。然后从左向右扫描,保持当前处理的区间[j,n]的逆序对不变,合理分配逆序对的来源,使得关于j的逆序对最少,从而保证最终构造出来的序列的字典序接近原序列。

     代码实现算法推荐:今天树状数组半价,推荐您使用这一款。它的这三个操作可以完全胜任这道题:

    find函数当然是用来找到第k大的啦。

    调用刘汝佳老师经常说的一句话:“本题非常经典,代码实现还有很多细节,请读者认真思考,强烈建议上机实践。(想一想,为什么)”

 #include<stdio.h>
#include<algorithm>
#define ll long long
#define go(i,a,b) for(int i=a;i<=b;i++)
#define ro(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
int n,a[],c[],s,S=;ll now,sum;
void ADD(int x,int d){while(x<=S)c[x]+=d,x+=x&-x;}
int Sum(int x){int R=;while(x)R+=c[x],x-=x&-x;return R;}
int find(int x){s=S;while(s)c[x+s]<now?x+=s,now-=c[x]:,s>>=;return x;}
int main()
{
scanf("%d",&n);while(S<=n)S<<=;
go(i,,n)scanf("%d",a+i);
ro(I,n,)
{
sum+=(now=Sum(a[I]));ADD(a[I],);
if(now<sum&&now<n-I&&sum<1ll*(n-I+)*(n-I)/)
go(i,I,n)i==I?now++:now=max(1ll*,sum-1ll*(n-i)*(n-i-)/),
sum-=now++,ADD(a[i]=find()+,-),I=;
}
go(i,,n)printf("%d ",a[i]);puts("");return ;
}//Paul_Guderian

这是我们的梦,一个真实的梦,
让每个人和每颗心紧紧相拥。—————汪峰《我们的梦》

【CODEVS 6384 大米兔学全排列】的更多相关文章

  1. 【NOIP2017 OFO】

    ·奇怪的标题可能预示着这一篇博文不是讲算法或者分享题目的吧. [一只情绪化的兔子]      今年的11月12日出奇地比去年温暖.两场比赛结束后的我们在临走前去尝试了OFO共享单车,在成都电子科技大学 ...

  2. 【NOIP2017 OFO(下)】

    ·我不知道对不对,只是不想让大米兔就这样离开.      by tkys_Austin;                    [另一只情绪化的兔子]        今年的11月12日NOIP提高组, ...

  3. [noip模拟]食物中毒<暴搜+状压优化>

    问题描述 Bqc经过一段时间的研究发现,要解这种毒需要一种特殊的药物.不幸的是,这种药物在 市面上不存在,没有办法Bqc只好亲自制得这种药物.它含有M种化学物质A1,A2,…,AM.现 在Bqc的手上 ...

  4. 【bzoj4445 scoi2015】小凸想跑步

    题目描述 小凸晚上喜欢到操场跑步,今天他跑完两圈之后,他玩起了这样一个游戏. 操场是个凸 nn 边形, nn 个顶点按照逆时针从 00 ∼ n - 1n−1 编号.现在小凸随机站在操场中的某个位置,标 ...

  5. Codeforces 148D 一袋老鼠 Bag of mice | 概率DP 水题

    除非特别忙,我接下来会尽可能翻译我做的每道CF题的题面! Codeforces 148D 一袋老鼠 Bag of mice | 概率DP 水题 题面 胡小兔和司公子都认为对方是垃圾. 为了决出谁才是垃 ...

  6. 【Begin】

    迫于无奈,我想提高写博速度.我要尽量压缩每道题的题解思路.最终我选择背叛大米兔,但是我支持它.因为它的每一篇博客耗时巨大,精贵的竞赛集训时间经不起它花:可同时精致的博客会带给来浏览的Oier们更多东西 ...

  7. codevs 1229 数字游戏(可重集的全排列)

    传送门 Description Lele 最近上课的时候都很无聊,所以他发明了一个数字游戏来打发时间.  这个游戏是这样的,首先,他拿出几张纸片,分别写上0到9之间的任意数字(可重复写某个数字),然后 ...

  8. codevs 1294 全排列 next_permuntation

    #include<bits/stdc++.h> using namespace std; #define ll long long #define pi (4*atan(1.0)) #de ...

  9. 全排列 (codevs 1294)题解

    [题目描述] 给出一个n, 请输出n的所有全排列(按字典序输出). [样例输入] 3 [样例输出] 1 2 3 1 3 2 2 1 3 2 3 1 3 1 2 3 2 1 [解题思路] 听说C++有作 ...

随机推荐

  1. django搭建web (三) admin.py -- 待续

    demo 关于模型myQuestion,myAnswer将在后述博客提及 # -*- coding: utf-8 -*- from __future__ import unicode_literals ...

  2. 项目Beta冲刺Day7

    项目进展 李明皇 今天解决的进度 部分数据传递和使用逻辑测试 林翔 今天解决的进度 服务器端查看个人发布的action,修改已发布消息状态的action,仍在尝试使用第三方云存储功能保存图片 孙敏铭 ...

  3. 《高级软件测试》JIRA使用手册(一)JIRA基本情况

    JIRA 官方网站为:https://www.atlassian.com/software/jira 中文代理网站为:https://www.jira.cn 现版本:v7.3.0 Atlassian公 ...

  4. js判断flash文件是否加载完毕

    轮询判断加载进度 img的加载完成有onload方法,一直不知道该怎么判断swf文件是否加载完毕了? 在应用中使用了轮询判断加载进度值PercentLoaded是否达到100,经测试,可以达到效果. ...

  5. kali rolling更新源之gpg和dirmngr问题

    1.编辑 /etc/apt/source.list gedit /etc/apt/sources.list 输入更新源,可以选任何可用更新源,这里设置官方源 deb http://http.kali. ...

  6. UML开发工具Rose ralation的破解安装,

    UML开发工具Rose ralation的在windows764破解安装, 安装下载还可以参考:http://www.cnblogs.com/leaven/p/3718361.html 跟大家分享怎么 ...

  7. JAVA 中一个非常轻量级只有 200k 左右的 RESTful 路由框架

    ICEREST 是一个非常轻量级只有 200k 左右的 RESTful 路由框架,通过 ICEREST 你可以处理 url 的解析,数据的封装, Json 的输出,和传统的方法融合,请求的参数便是方法 ...

  8. zuul入门(1)zuul 的概念和原理

    一.zuul是什么 zuul 是netflix开源的一个API Gateway 服务器, 本质上是一个web servlet应用. Zuul 在云平台上提供动态路由,监控,弹性,安全等边缘服务的框架. ...

  9. Spark入门(1-3)Spark的重要概念

    1.什么是弹性分布式数据集? Spark提出了RDD(Resilient Distributed Datasets)这么一个全新的概念,RDD弹性分布式数据集是并行.容错的分布式数据结构:可以将RDD ...

  10. 05_Linux目录文件操作命令2_我的Linux之路

    这一节我们继续来学习Linux中对文件和目录的操作命令 mkdir 创建目录 mkdir (选项)(参数) 在Linux端可以使用mkdir来创建目录,如果你没有加其他的路径名,那么默认是在当前目录下 ...