POJ 3761 Bubble Sort 冒泡排序的扩展

给一个序列,如果经过k次冒泡能使其变为单增序列,则称该序列为k回合冒泡序列

现在给你n,k, 问在n的全排列中,k回合冒泡序列有多少个

这题看规模就是要推一个公式出来

discuss里的一个解法非常好,让人可以理解

对于n个元素,假设为{0,1,...n- 1},可以发现
对于任意一个排列,假设L(i) 表示位置i上的元素的前面有多少数字比它大, 那么得到了一个L序列。
那么可以知道 交换的轮数 =  max{ L(i) } (0 <= i < n)

并且可以发现,对于所有n!种序列,其L序列满足:{[0,0],[0,1],[0,2]...[0,n-1] }...(1)

[a,b] 表示值在[a,b] 之间,包含

对于满足(1)的任意一个L序列,必然可以构造出一个对应的序列。

于是可以知道题目所求的就是max{L[i]} = k的种类数
于是我们考虑
1 * 2 * 3 .. * k  * (k + 1) ^ (n - k),就是后面的从第k项开始,全部取[0,k],前面任意取
之后扣除 1 * 2 * 3 * ... * k * k^(n - k + 1) ,就是后面第k项开始 [0,k - 1],前面任意取

于是ans = k! * ((k + 1) ^ (n - k) - k^(n - k))

对于k!,o(1000000)预处理即可

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <cmath>
#include <algorithm>
#include <map>
#include <ctime>
#define MAXN 222
#define MAXM 6122222
#define INF 1000000001
using namespace std;
int fac[1111111];
int mod = 20100713;
long long fastmod(long long a, long long b, long long c){
    long long ret = 1;
    a %= c;
    for(; b; b >>= 1, a = (a * a) % c)
        if(b & 1)
            ret = ret * a % c;
    return ret;
}
int main() {
    fac[0] = 1;
    for(int i = 1; i <= 1000000; i++) {
        long long tmp = (long long)fac[i - 1] * (long long)i % mod;
        fac[i] = tmp;
    }
    int T, n, k;
    scanf("%d", &T);
    while(T--) {
        scanf("%d%d", &n, &k);
        long long tmp = (long long)fac[k] * (fastmod(k + 1, n - k, mod) - fastmod(k, n - k, mod) + (long long)mod) % mod;
        printf("%I64d\n", tmp);
    }
    return 0;
}
时间: 2024-11-08 21:35:19

POJ 3761 Bubble Sort 冒泡排序的扩展的相关文章

快速幂取模 POJ 3761 bubble sort

题目传送门 1 /* 2 题意:求冒泡排序扫描k次能排好序的全排列个数 3 数学:这里有一个反序列表的概念,bj表示在j左边,但大于j的个数.不多说了,我也是看网上的解题报告. 4 详细解释:http://blog.csdn.net/cscj2010/article/details/7820906 5 */ 6 #include <cstdio> 7 #include <algorithm> 8 #include <cstring> 9 #include <cma

POJ 3761 Bubble Sort

题目链接:https://vjudge.net/problem/POJ-3761 转自:https://blog.csdn.net/cscj2010/article/details/7820906 题目大意 含 n 个不同元素的排列恰好经过 k 趟冒泡排序变得有序.问原数组有多少种排列情况? 分析 第一眼看上去觉得是个 DP,最后发现是个数学题,认栽... 首先,定义 f(x) 表示在数组中位于元素 x 左面且大于 x 的个数.那么有$0 \leq f(x) \leq n - x$. 由题意得$

bubble sort 冒泡排序

#include <iostream> #include <list> #include <algorithm> using namespace std; template< typename T > void BubbleSort(list<T>& li) { list<T>::iterator it_left = li.begin(); list<T>::iterator it_right = li.begin

POJ 3761:Bubble Sort——组合数学

题目大意:众所周知冒泡排序算法多数情况下不能只扫描一遍就结束排序,而是要扫描好几遍.现在你的任务是求1~N的排列中,需要扫描K遍才能排好序的数列的个数模20100713.注意,不同于真正的冒泡排序算法,只要数列有序就立刻停止,而不用再检验一遍. 估计多数人都是找规律吧,先看出递推,然后求出通项……这个题只有找出通项公式才能通过,所以首先公布答案: K!((K + 1) ^ (N - K) - K ^ (N - K)) 好吧,现在让我们来证明一下. 首先定义函数d(x),对于1~N的一个排列,d(

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

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

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

Java中的经典算法之冒泡排序(Bubble Sort) 原理:比较两个相邻的元素,将值大的元素交换至右端. 思路:依次比较相邻的两个数,将小数放在前面,大数放在后面.即在第一趟:首先比较第1个和第2个数,将小数放前,大数放后.然后比较第2个数和第3个数,将小数放前,大数放后,如此继续,直至比较最后两个数,将小数放前,大数放后.重复第一趟步骤,直至全部排序完成. 举例说明:要排序数组:int[] arr={6,3,8,2,9,1}; 第一趟排序: 第一次排序:6和3比较,6大于3,交换位置:  

冒泡排序(Bubble Sort)

常见的排序算法有Bubble Sort.Merge Sort.Quick Sort 等,所有排序算的基本法思想都是把一个无限大的数据规模通过算法一步步缩小,指导最后完成排序. 这里分享一下Buuble Sort算法,php版本的.冒泡排序不适合在待排序的数据集特别大的情况下,这里只是一个简易的demo,待排序的数据在10以内. 冒泡排序算法有2种极端的情况所导致的算法复杂度是不一样的: 所有的数据集都是有序的,则此时通过算法优化可以是算法的复杂度从 O(n^2) 将至 O(n) 所有的数据集都是

HDU 5775 Bubble Sort(冒泡排序)

HDU 5775 Bubble Sort(冒泡排序) Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)   Problem Description - 题目描述 P is a permutation of the integers from 1 to N(index starting from 1).Here is the code of Bubble Sort in C++.

冒泡排序(Bubble Sort)

冒泡排序(Bubble Sort),是一种计算机科学领域的较简单的排序算法. 它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来.走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成. 这个算法的名字由来是因为越大的元素会经由交换慢慢“浮”到数列的顶端,故得名. 算法原理 冒泡排序算法的运作如下:(从后往前) 比较相邻的元素.如果第一个比第二个大,就交换他们两个. 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对.在这一点,最后的元素应