[XSY 1549] 冒泡排序

题意

  我们对序列 A 进行如下的冒泡排序.

m = 0;
while (!sorted(A)) {
    m++;
    for (int i = m-1; i >= 1; i--)
        if (A[i] > A[i+1])
            swap(A[i], A[i+1]);
}

  我们定义 m 为对 A 进行冒泡排序的难度.

  求在所有满足排序难度为 m 的 [1, n] 的排列中, 字典序第 K 小的排列.

  0 <= m <= n-1 < 20 .

  保证 K 合法.

分析

  记 $d_i = \sum_{j}[i < j][a_i > a_j]$ , 即以 i 为左端点的逆序对数.

  我们通过观察可以发现, 排序难度即为 $\max_i d_i$ .

  现在相当于找逆序对数的最大值为 m 的第 K 个排列.

  我们先研究一下, 逆序对数为 m 的排列个数, 记作 G(n, m) .

  我们考虑差分, 设逆序对数不超过 m 的排列个数为 g(n, m) .

  当 n < m 时, g(n, m) = n! ; 当 n >= m 时, g(n, m) = m! (m+1) ^ {n - m} .

  当 m = 0 时, G(n, m) = g(n, m) ; 当 m > 0 时, G(n, m) = g(n, m) - g(n, m-1) .

  接下来的做法类似数位DP .

  我们考虑从高位到低位, 枚举每一位的取值, 算个数, 若个数多于 K , 那么减去, 否则确定.

  我们发现, 之后若有 n 个数, 不用管数值是多少, 直接离散成 1 ~ n 即可.

  需要记录一个 tag , 表示当前是否取到 m , 注意当前位只能取 1 ~ min(bit, m+1) .

实现

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <cstdlib>
 4 #include <cctype>
 5 #include <algorithm>
 6 using namespace std;
 7 #define F(i, a, b) for (register int i = (a); i <= (b); i++)
 8 #define LL long long
 9
10 const int N = 25;
11
12 int n, m; LL K;
13 bool v[N]; int List[N];
14
15 inline LL Pow(int x, int y) { LL mul = 1; F(i, 1, y) mul *= x; return mul; }
16 inline LL Fac(int x) { LL mul = 1; F(i, 1, x) mul *= i; return mul; }
17 inline LL g(int n, int m) { return m >= n ? Fac(n) : Fac(m) * Pow(m+1, n-m); }
18 inline LL G(int n, int m) { return !m ? g(n, m) : g(n, m) - g(n, m-1); }
19 // 0 <= m <= n-1 < 20
20
21 inline void Mark(int bit, int w) {
22     for (int x = 0, cnt = 0; x < n; ) {
23         cnt += !v[++x];
24         if (cnt == w) { v[x] = true, List[bit] = x; return; }
25     }
26 }
27
28 int main(void) {
29     #ifndef ONLINE_JUDGE
30         freopen("bubble.in", "r", stdin);
31     #endif
32
33     scanf("%d %d %lld", &n, &m, &K);
34
35     bool Gain = false;
36     for (int bit = n; bit >= 1; bit--) {
37         bool done = false; int w;
38         for (w = 1; w < min(m + 1, bit) && !done; w++) {
39             LL cnt = (Gain ? g(bit-1, m) : G(bit-1, m));
40             if (K <= cnt) done = true; else K -= cnt;
41         }
42         done ? w-- : Gain = true;
43         Mark(bit, w);
44     }
45
46     for (int bit = n; bit >= 1; bit--)
47         printf("%d ", List[bit]);
48     puts("");
49
50     return 0;
51 }
时间: 2024-12-12 20:06:05

[XSY 1549] 冒泡排序的相关文章

经典排序算法 - 冒泡排序Bubble sort

 原文出自于 http://www.cnblogs.com/kkun/archive/2011/11/23/bubble_sort.html 经典排序算法 - 冒泡排序Bubble sort 原理是临近的数字两两进行比较,按照从小到大或者从大到小的顺序进行交换, 这样一趟过去后,最大或最小的数字被交换到了最后一位, 然后再从头开始进行两两比较交换,直到倒数第二位时结束,其余类似看例子 例子为从小到大排序, 原始待排序数组| 6 | 2 | 4 | 1 | 5 | 9 | 第一趟排序(外循环) 第

算法 排序lowB三人组 冒泡排序 选择排序 插入排序

参考博客:基于python的七种经典排序算法   [经典排序算法][集锦]     经典排序算法及python实现 首先明确,算法的实质 是 列表排序.具体就是操作的列表,将无序列表变成有序列表! 一.排序的基本概念和分类 所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作.排序算法,就是如何使得记录按照要求排列的方法. 排序的稳定性: 经过某种排序后,如果两个记录序号同等,且两者在原无序记录中的先后秩序依然保持不变,则称所使用的排序方法是稳定的,反之是不稳定

php实现冒泡排序

一个程序应包括:对数据的描述:在程序中要指定数据的类型和数据的组织形式,即数据结构(data structure).对操作的描述:即操作步骤,也就是算法(algorithm).Nikiklaus Wirth提出的公式:程序=数据结构+算法作为一个程序员必须得懂点算法啊,就从最简单的开始吧=>冒泡排序 维基百科的说法 冒泡排序(英语:Bubble Sort,台湾另外一种译名为:泡沫排序)是一种简单的排序算法.它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来.走访数列

算法之冒泡排序(Java示例)

冒泡排序(英语:Bubble Sort) 是一种简单的排序算法.它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来.走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成.这个算法的名字由来是因为越小的元素会经由交换慢慢"浮"到数列的顶端. 动画示意 实现示例 Java 1 public class BubbleSortExample { 2 3 static void bubbleSort(int[] arr){ 4 int len =

python 算法中的--冒泡排序

#列表每两个相邻的数,如果前面的比后面的大,那么就交换这两个数# shuffle() 方法将序列的所有元素随机排序. import random def bubble_sort(li): for i in range(len(li)-1): #i代表趟 for j in range(len(li)-i-1): #j列表 if li[j]>li[j+1]: li[j],li[j+1]=li[j+1],li[j] data=list(range(5)) random.shuffle(data) #打

【2017-02-28】冒泡排序

冒泡排序就是比大小,若前者大于后者,则两者交换位置.用两个For循环嵌套来实现 using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace 数组 { class Program { static void Main(string[] args) { //冒泡排序 3 5 1 2 4 (12345) //思路:第一个for循环执行第一次的时候把第一个数拿出来和后面的数

C语言之冒泡排序算法

一.什么是冒泡排序?冒泡排序(Bubble Sort),是一种计算机科学领域的较简单的排序算法.它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来.走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成.这个算法的名字由来是因为越大的元素会经由交换慢慢"浮"到数列的顶端,故名.二.冒泡排序的原理   冒泡排序原理是临近的数字两两进行比较,按照从小到大或者从大到小的顺序进行交换,这样一趟过去后,最大或最小的数字被交换到了最后一位,然后再从头

冒泡排序总结

package Test5; public class maoPai { public static void main(String[] args) { int a[]={56,23,78,1,0,9,46,20}; maoPai.paiXu(a); for(int i=0;i<a.length;i++){ System.out.print(a[i]+" "); } } public static void paiXu(int a[]){ boolean t=true;A冒泡排

利用冒泡排序实现一串字符串从小到大的排序

实现B/S架构,输入一串字母或数字,将它们按从小到大排序,排序算法在服务端实现. 以下是实现: Test.java import java.io.IOException;import java.io.PrintWriter; import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.ser