题目大意:众所周知冒泡排序算法多数情况下不能只扫描一遍就结束排序,而是要扫描好几遍。现在你的任务是求1~N的排列中,需要扫描K遍才能排好序的数列的个数模20100713。注意,不同于真正的冒泡排序算法,只要数列有序就立刻停止,而不用再检验一遍。

估计多数人都是找规律吧,先看出递推,然后求出通项……这个题只有找出通项公式才能通过,所以首先公布答案:

K!((K + 1) ^ (N - K) - K ^ (N - K))

好吧,现在让我们来证明一下。

首先定义函数d(x),对于1~N的一个排列,d(x)表示第x个数前面有多少个数字大于该数。

比如说对于3 2 4 1 5,有d(1) = 0,d(2) = 1,d(3) = 0,d(4) = 3,d(5) = 0。

现在我们来证明d(x)函数的两条性质:

(一)对于一个排列,对于所有x <= N,有d(x) = 0是这个排列是有序的充要条件。

如果存在1 <= i, j <= N,使得i < j,ai > aj,那么由于aj前面有ai大于它,故d(j) >= 1。而这与d(j) = 0矛盾,反之亦然。所以说命题成立。

(二)冒泡排序的每次扫描的结果是,对于非零的d(x)值,这个位置的d(x)会且只会减少1。

考虑某个非零的d(x)值。由于d(x) >= 1,所以必然存在整数i∈[1, x - 1],满足ai > ax。设m为a1, a2, ..., a(x -1)中的最大值,位置为i,则必有m > ax。那么,在扫描到a(x - 1)和ax的时候,由于前面的交换,必然有a(x - 1) = m。

原因是如果前面的交换将m交换到了a(x - 2)的位置,那么由于m > a(x - 1),那么ai必然能够被交换到a(x - 1)的位置。故由数学归纳法,只要m能够被交换到a(i + 1)即可。而在交换之前a(i - 1) < m,m与a(i - 1)不发生交换;同时必然有m > a(i + 1),m一定会被交换到a(i + 1),故该结论成立,从而扫描a(x - 1)和ax的时候a(x - 1) = m。

这时由于m > ax,m与ax之间要交换,交换的效果由于ax前面比ax小的数字减少了一个,d(x)减小了1。所以说d(x)在这个过程中必会减少。

而另一方面,完成了m与ax的这次交换之后,这一次扫描显然就不会再交换ax的值了(这时ax位置上的值已经是m了)。所以说,d(x)也只能减少1。这就证明完毕。

证明了d(x)函数的这个性质之后,我们就可以得出对于1~n的一个排列,它所需要的冒泡排序的扫描次数为

K = max (d(i), 1 <= i <= N)

而这个结论很显然,因为只有经过K次扫描,所有位置的d值才能都变为0。

到此,我们成功地将冒泡排序的次数问题转化为d(x)值满足条件的数列的问题。原问题也就转化成了有多少个排列使得其中最大的d(x)值恰好为K。然而这也是复杂的,所以说我们不妨先解决有多少个排列使得其中最大的d(x)值不大于K。

首先可以确定N >= K + 1,否则不可能出现某个位置前面有K个数大于它。

然后决定原数列中1的位置。显而易见,如果最小数的位置为x,则其d(x) = x - 1。而d(x) <= K,故x <= K + 1,也就是说1有K + 1种放置方法;而放置2的时候,我们完全可以考虑一个新的排列2~N,这时2有K + 1种放置方法,然后再把1插到位置1~K + 1,而不影响其它数的d值。所以说,前N - K个数的放置方法的种类有

(K + 1) ^ (N - K)

之后只需要考虑N - K + 1 ~ N的排列即可。然而,由于整个数列只有K个数字,不可能出现某个d值大于K + 1。所以说排列方法有K!种。故,所有位置d值不大于K的排列的方案数有

K!((K + 1) ^ (N - K))

但是这是不大于K的排列数量,恰好为K的有怎么办呢?很简单,只需要减去不大于K - 1的排列数量便可。所以最后的答案为

K!((K + 1) ^ (N - K)) - (K - 1)!(K ^ (N - K + 1))

化简之后我们就得到

K!((K + 1) ^ (N - K) - K ^ (N - K))

这就是原来的式子,它的正确性就证明完毕。

然后代码就是小意思了:

#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;

const int mod = 20100713;

__int64 power (int k, int n)
{
    __int64 r = k, ans = 1;
    while (n)
    {
        if (n & 1) ans = (ans * r) % mod;
        r = (r * r) % mod;
        n >>= 1;
    } return ans;
}

__int64 factorial[1000010];

int main ()
{
    int t, n, k;
    __int64 ans;
    factorial[0] = 1;
    for (int i = 1; i < 1000010; i++)
        factorial[i] = (factorial[i - 1] * i) % mod;
    scanf("%d", &t);
    for (; t > 0; t--)
    {
        scanf("%d %d", &n, &k);
        n -= k;
        ans = (power(k + 1, n) - power(k, n)) % mod;
        if (ans < 0) ans += mod;
        ans = (ans * factorial[k]) % mod;
        printf("%I64d\n", ans);
    }
    return 0;
}

POJ 3761:Bubble Sort——组合数学的更多相关文章

  1. 快速幂取模 POJ 3761 bubble sort

    题目传送门 /* 题意:求冒泡排序扫描k次能排好序的全排列个数 数学:这里有一个反序列表的概念,bj表示在j左边,但大于j的个数.不多说了,我也是看网上的解题报告. 详细解释:http://blog. ...

  2. POJ 3761 Bubble Sort(乘方取模)

    点我看题目 题意 : 冒泡排序的原理众所周知,需要扫描很多遍.而现在是求1到n的各种排列中,需要扫描k遍就变为有序的数列的个数,结果模20100713,当然了,只要数列有序就扫描结束,不需要像真正的冒 ...

  3. POJ 3761 Bubble Sort 快速幂取模+组合数学

    转载于:http://www.cnblogs.com/767355675hutaishi/p/3873770.html 题目大意:众所周知冒泡排序算法多数情况下不能只扫描一遍就结束排序,而是要扫描好几 ...

  4. poj 3761 bubble sort (排列组合)

    #include<cstdio> #include<cstring> #define ll long long #define mod 20100713 ; ll a[maxn ...

  5. POJ 3761 Bubble Sort

    题目链接:https://vjudge.net/problem/POJ-3761 转自:https://blog.csdn.net/cscj2010/article/details/7820906 题 ...

  6. poj 3761 Bubble Sort_快速幂

    题意:问你冒泡排序第i次排序,一共排了多少次 套公式K!((K + 1) ^ (N - K) - K ^ (N - K)) #include <iostream> #include< ...

  7. POJ3761 Bubble Sort (组合数学,构造)

    题面 Bubble sort is a simple sorting algorithm. It works by repeatedly stepping through the list to be ...

  8. Java中的经典算法之冒泡排序(Bubble Sort)

    Java中的经典算法之冒泡排序(Bubble Sort) 神话丿小王子的博客主页 原理:比较两个相邻的元素,将值大的元素交换至右端. 思路:依次比较相邻的两个数,将小数放在前面,大数放在后面.即在第一 ...

  9. Bubble Sort (5775)

    Bubble Sort Problem Description   P is a permutation of the integers from 1 to N(index starting from ...

随机推荐

  1. Lombok 插件安装和使用

    引言 以前的 Java 项目中,充斥着太多毫无技术含量的代码,比如类属性的 getter/setter/toString 方法,还有就是异常处理.I/O 流的关闭操作等.这些样板代码虽然可以通过 ID ...

  2. 完全理解Python 迭代对象、迭代器、生成器

    在了解Python的数据结构时,容器(container).可迭代对象(iterable).迭代器(iterator).生成器(generator).列表/集合/字典推导式(list,set,dict ...

  3. 七牛云-上传、删除文件,工具类(Day49)

    要求: 1. java1.8以上 2. Maven: 这里的version指定了一个版本范围,每次更新pom.xml的时候会尝试去下载7.5.x版本中的最新版本,你可以手动指定一个固定的版本. < ...

  4. tar压缩文件 .tar.gz

    打包并压缩文件 tar -zcf ansible.tar.gz ansible/* z    gzip属性 c    建立压缩文件 f    指定文件名 v    显示过程 解压文件 tar xzf ...

  5. 去除HTML中的标签内容

    采集后的数据都带有'<>'html标签: <img src="http://i4.hdfimg.com/www/images/giftrans/3d/da/7b/18414 ...

  6. CVPR2019论文解读:单眼提升2D检测到6D姿势和度量形状

    CVPR2019论文解读:单眼提升2D检测到6D姿势和度量形状 ROI-10D: Monocular Lifting of 2D Detection to 6D Pose and Metric Sha ...

  7. MindSpore图像分类模型支持(Lite)

    MindSpore图像分类模型支持(Lite) 图像分类介绍 图像分类模型可以预测图片中出现哪些物体,识别出图片中出现物体列表及其概率. 比如下图经过模型推理的分类结果为下表: 类别 概率 plant ...

  8. Geo-CNN的三维点云

    Geo-CNN的三维点云 Modeling Local Geometric Structure of 3D Point Clouds using Geo-CNN 摘要 深度卷积神经网络(CNNs)的最 ...

  9. TVM vs TensorRT比较

    TVM vs TensorRT比较 如果理解正确的话,TensorRT和TVM会加快预测速度. TensorRT优化预测GPU和TVM优化预测几乎所有平台支持GPU,ARM,Mobile... 两者在 ...

  10. H.265 HD 和H.265 4K Video Encoder IP Core

    H.265 HD 和H.265 4K Video Encoder IP Core H.265 HD Video Encoder IP Core(H.265 HD Video/Audio Encoder ...