poj 3761 Bubble Sort
2012-08-13 16:19
337 查看
问题描述如下:
一个具有n个元素的排列,经过k趟bubble sort排到有序状态。求出满足此条件的排列个数。
首先,了解反序表的概念。《计算机程序设计艺术》第三卷5.1.1反序部分有说明。简述如下:a1,a2,...,an是集合{1,2,...,n}的一个排列。令bj为位于j左边但是大于j的元素个数,就能得到排列a1,a2,...,an的反序表b1,b2,...,b3。比如说:排列
5 9 1 8 2 6 4 7 3
有反序表
位置: 1 2 3 4 5 6 7 8 9
b 2 3 6 4 0 2 2 1 0
不管什么样子的排列,只要可以比较大小,就可以映射到集合{1,2,...,n}上的一个排列。不难发现,每一趟bubble sort ,都会将这一趟之前反序数大于0的元素的反序数减1。经过k趟之后,所有元素的反序数均为0,也就是说,反序表为n个0,亦即有序状态。因此,题目可以演化为,n个元素的排列,反序表中最大值为k,求这样的排列有多少种。
易知,第i个元素的反序数取值范围是[0,n-i],还注意到一个事实,就是:每个元素的反序数取值是相互独立。为什么呢?事实上我开始以为是不独立的,但是验证了几个例子以后,我推翻自己的想法。当然这只是直觉上的。但是可以从《计算机程序设计艺术》第三卷反序部分得到一点理论支撑。引用书上的话“一张反序表唯一的确定一个排列”(我没有细看这个事实的证明)。因此,反序表和排列之间一一对应。全排列个数是n!,因此反序表的个数也是n!,这只有在取值相互独立的情况下得到。
回到题目,反序数最大为k。那么当n-i<=k,即i>=n-k的时候,元素i可随意放。因为不管怎么放,他们的反序数都不会大于k,取值的个数由i来决定。当i<n-k时候,这些元素的反序数只可以在[0,k]之间选择。这样,我把n个元素分为两类来讨论,前面一类元素有k+1(即i = 1~k+1)个,后面一类有n-k-1(即i=n-k-1~n)个元素。先考虑前面一种情况,我们对前面k+1个元素进行全排列,他们的反序数一定在0~k之间,那么就有(k+1)!种排序的方法。后面一类,我们可以与前面的元素进行对调,但是他们的值之差不能超过k(我们要保证他们的反序数在0~k之间)那么有(k+1)种选择去对调,因此有(k+1)^(n-k-1)种方案。由乘法定理,易得k!*(k+1)^(n-k)。
但是,这不是最终答案。上面的结果,只是说经过不超过k趟排到有序状态。并不符合题意。因此,必须保证有一个元素的反序数为k。最好的做法就是计算出不超过k-1趟就排到有序状态的排列数,减掉。很容易利用刚才的结论,得到不超过k-1趟就排到有序状态的排列数为:(k-1)!*(k)^(n-k+1)。两者想减,即得到结果:
k!*((k + 1)^(n - k) - k ^(n - k))。
View Code
一个具有n个元素的排列,经过k趟bubble sort排到有序状态。求出满足此条件的排列个数。
首先,了解反序表的概念。《计算机程序设计艺术》第三卷5.1.1反序部分有说明。简述如下:a1,a2,...,an是集合{1,2,...,n}的一个排列。令bj为位于j左边但是大于j的元素个数,就能得到排列a1,a2,...,an的反序表b1,b2,...,b3。比如说:排列
5 9 1 8 2 6 4 7 3
有反序表
位置: 1 2 3 4 5 6 7 8 9
b 2 3 6 4 0 2 2 1 0
不管什么样子的排列,只要可以比较大小,就可以映射到集合{1,2,...,n}上的一个排列。不难发现,每一趟bubble sort ,都会将这一趟之前反序数大于0的元素的反序数减1。经过k趟之后,所有元素的反序数均为0,也就是说,反序表为n个0,亦即有序状态。因此,题目可以演化为,n个元素的排列,反序表中最大值为k,求这样的排列有多少种。
易知,第i个元素的反序数取值范围是[0,n-i],还注意到一个事实,就是:每个元素的反序数取值是相互独立。为什么呢?事实上我开始以为是不独立的,但是验证了几个例子以后,我推翻自己的想法。当然这只是直觉上的。但是可以从《计算机程序设计艺术》第三卷反序部分得到一点理论支撑。引用书上的话“一张反序表唯一的确定一个排列”(我没有细看这个事实的证明)。因此,反序表和排列之间一一对应。全排列个数是n!,因此反序表的个数也是n!,这只有在取值相互独立的情况下得到。
回到题目,反序数最大为k。那么当n-i<=k,即i>=n-k的时候,元素i可随意放。因为不管怎么放,他们的反序数都不会大于k,取值的个数由i来决定。当i<n-k时候,这些元素的反序数只可以在[0,k]之间选择。这样,我把n个元素分为两类来讨论,前面一类元素有k+1(即i = 1~k+1)个,后面一类有n-k-1(即i=n-k-1~n)个元素。先考虑前面一种情况,我们对前面k+1个元素进行全排列,他们的反序数一定在0~k之间,那么就有(k+1)!种排序的方法。后面一类,我们可以与前面的元素进行对调,但是他们的值之差不能超过k(我们要保证他们的反序数在0~k之间)那么有(k+1)种选择去对调,因此有(k+1)^(n-k-1)种方案。由乘法定理,易得k!*(k+1)^(n-k)。
但是,这不是最终答案。上面的结果,只是说经过不超过k趟排到有序状态。并不符合题意。因此,必须保证有一个元素的反序数为k。最好的做法就是计算出不超过k-1趟就排到有序状态的排列数,减掉。很容易利用刚才的结论,得到不超过k-1趟就排到有序状态的排列数为:(k-1)!*(k)^(n-k+1)。两者想减,即得到结果:
k!*((k + 1)^(n - k) - k ^(n - k))。
View Code
#include<iostream> #include<cstdio> #include<cstdlib> #include<algorithm> #include<cmath> #include<queue> #include<set> #include<map> #include<cstring> #include<vector> #include<string> #define LL long long #define MOD 20100713 using namespace std; LL A[1000024]; void Init( ) { A[0] = 1LL; for( LL i = 1 ; i <= 1000000LL; i++ ) A[i] = ( i * A[i-1] )%MOD; } LL Pow( LL n,LL a ) { LL ans = 1; while( n ) { if( n&1 ) ans = (ans*a)%MOD; a = (a*a)%MOD; n >>= 1; } return ans; } int main( ) { int T; LL n,k; Init(); while( scanf( "%d",&T )==1 ) { while( T-- ) { scanf( "%I64d %I64d",&n,&k ); LL ans = (Pow( n-k , k+1 ) - Pow( n - k , k )+MOD)%MOD; printf( "%I64d\n",(ans*A[k])%MOD ); } } //system( "pause" ); return 0; }
相关文章推荐
- poj 3761 Bubble Sort
- POJ 3761 Bubble Sort 快速幂取模+组合数学
- POJ 3761 Bubble Sort
- POJ 3761 Bubble Sort(乘方取模)
- POJ 3761 Bubble Sort (用反序表分析排列数)
- POJ 3761 Bubble Sort (乘方取模)
- 快速幂取模 POJ 3761 bubble sort
- poj 3761 Bubble Sort_快速幂
- poj 3761 bubble sort (排列组合)
- poj 3761 Bubble Sort_快速幂
- POJ3761 Bubble Sort
- POJ 3761 Bubble Sort
- poj3761 bubble sort
- POJ 3968|UVALive 4992|HDU 3761|UVA 1475|Jungle Outpost|二分|半平面交
- POJ 3761 not(思路+想法) 题
- poj 3761
- poj 3761 Panda's Birthday Present (数学公式推导~~推?)
- POJ 3761:Bubble Sort——组合数学
- POJ 3761 Bubble Sort 冒泡排序的扩展
- poj 3761 反逆序数+快速取模+阶乘预处理